Как я могу объединить два словаря, не получая исключение ArgumentException для ключа?

Я не могу понять, как сохранить ключи и значения в словаре, когда пытаюсь объединить два словаря. Я продолжаю получать ArgumentException из-за дубликата ключа. Когда ключ совпадает, я просто хотел бы добавить значение на =+ kvp.value;

У меня есть список словарей, где

1-й словарь = kvp = "jump", 2;

2ndDictionary = kvp = "jump", 4;

Мне нравится объединять их и получать что-то вроде: Словарь = kvp = "jump", 6;

Что я могу позже добавить в свой список словарей

Я попытался запустить то, что нашел в ветке StackOverflow.

foreach (var dict in listOfDict)
{
         dict.SelectMany(d => d)
            .ToLookup(pair => pair.Key, pair => pair.Value)
            .ToDictionary(group => group.Key, group => group.First());
}

Но я продолжаю получать.

не может быть выведено из использования. Попробуйте указать аргументы типа явно.

Я хочу избежать получения всех ключей и всех значений в отдельных списках, которые я позже просматриваю, чтобы добавить ключ и значение в новый словарь.

Шаблоны Angular PrimeNg
Шаблоны Angular PrimeNg
Как привнести проверку типов в наши шаблоны Angular, использующие компоненты библиотеки PrimeNg, и настроить их отображение с помощью встроенной...
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Если вы веб-разработчик (или хотите им стать), то вы наверняка гик и вам нравятся "Звездные войны". А как бы вы хотели, чтобы фоном для вашего...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Начала с розового дизайна
Начала с розового дизайна
Pink Design - это система дизайна Appwrite с открытым исходным кодом для создания последовательных и многократно используемых пользовательских...
Шлюз в PHP
Шлюз в PHP
API-шлюз (AG) - это сервер, который действует как единая точка входа для набора микросервисов.
14 Задание: Типы данных и структуры данных Python для DevOps
14 Задание: Типы данных и структуры данных Python для DevOps
проверить тип данных используемой переменной, мы можем просто написать: your_variable=100
2
0
66
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Если вы получаете исключение из-за повторяющихся ключей, то похоже, что у вас есть дубликаты ключей!

Вы проверили два словаря, прежде чем пытаться их объединить? Простой вызов =+ kvp.value без проверки того, есть ли уже ключ с таким именем в первом словаре, скорее всего, будет вашей проблемой.

Вам нужно проверить существующую запись с этим ключом и, если она найдена, выполнить любое действие, подходящее для вашего сценария (например, игнорировать, перезаписать, попросить пользователя принять решение и т. д.)

Если вам нравится подход LINQ, я бы сделал что-то вроде этого:

    var dictionaries = new List<Dictionary<string, int>>(); // this is the list of dictionaries you want to merge
    var unifiedDictionary = new Dictionary<string, int>(); // this is the dictionary where you merge and add the values

    foreach (var kvp in dictionaries.SelectMany(dictionary => dictionary))
    {
        if (unifiedDictionary.ContainsKey(kvp.Key))
        {
            unifiedDictionary[kvp.Key] += kvp.Value;
        }
        else
        {
            unifiedDictionary.Add(kvp.Key, kvp.Value);
        }
    }

Однако, если это слишком сложно читать (я не всегда являюсь поклонником чрезмерного использования LINQ над явными блоками кода), вы можете использовать подход for-loop:

    var dictionaries = new List<Dictionary<string, int>>(); // this is the list of dictionaries you want to merge
    var unifiedDictionary = new Dictionary<string, int>(); // this is the dictionary where you merge and add the values

    foreach (var dictionary in dictionaries)
    {
        foreach (var kvp in dictionary)
        {
            if (unifiedDictionary.ContainsKey(kvp.Key))
            {
                unifiedDictionary[kvp.Key] += kvp.Value;
            }
            else
            {
                unifiedDictionary.Add(kvp.Key, kvp.Value);
            }
        }
    }

Надеюсь, это поможет вам. Если нужна дополнительная помощь и пояснения, пожалуйста, сообщите мне.

Ответ принят как подходящий

Простейшее расширение списка словаря двойных значений с использованием Linq:

public static class ExtListOfDict {
    public static Dictionary<TKey, double> SumValue1<TKey>(this List<Dictionary<TKey, double>> list)        
        => list?.SelectMany(i => i).ToLookup(i => i.Key, i => i.Value).ToDictionary(i => i.Key, i => i.Sum());

}

без Линка:

public static Dictionary<TKey, double> SumValue2<TKey>(this List<Dictionary<TKey, double>> list) {
    if(list?.Count > 0) {
        var dir = new Dictionary<TKey, double>(list[0]);
        for(var i = 1; i < list.Count; i++) 
            foreach (var kv in list[i])
                if (dir.TryGetValue(kv.Key, out double sum))
                    dir[kv.Key] = sum + kv.Value; 
                else 
                    dir.Add(kv.Key, kv.Value);                    
        return dir;
    } else
        return null;
}

Простой, но довольно неэффективный.

Theodor Zoulias 20.11.2022 01:01

В самом деле? покажи лучше...

Adam Silenko 20.11.2022 01:23

Решение Габриэля Станку значительно эффективнее вашего подхода ToLookup+ToDictionary.

Theodor Zoulias 20.11.2022 01:33

Подход «без LINQ», вероятно, можно было бы дополнительно оптимизировать с помощью метода CollectionsMarshal.GetValueRefOrAddDefault (.NET 6).

Theodor Zoulias 20.11.2022 01:48

наверное да, пожалуйста напишите ответ

Adam Silenko 20.11.2022 01:52

Вот решение, основанное на CollectionsMarshal.GetValueRefOrAddDefault API (.NET 6) и на интерфейсе INumber<TSelf> (.NET 7):

public static Dictionary<TKey, TValue> ToSumDictionary<TKey, TValue>(
    this IEnumerable<Dictionary<TKey, TValue>> dictionaries)
    where TValue : struct, INumber<TValue>
{
    ArgumentNullException.ThrowIfNull(dictionaries);
    Dictionary<TKey, TValue> result = null;
    foreach (var dictionary in dictionaries)
    {
        if (result is null)
        {
            result = new(dictionary, dictionary.Comparer);
            continue;
        }
        if (!ReferenceEquals(dictionary.Comparer, result.Comparer))
            throw new InvalidOperationException("Incompatible comparers.");
        foreach (var (key, value) in dictionary)
        {
            ref TValue refValue = ref CollectionsMarshal
                .GetValueRefOrAddDefault(result, key, out bool exists);
            refValue = exists ? refValue + value : value;
        }
    }
    result ??= new();
    return result;
}

Ключ каждого KeyValuePair<TKey, TValue> в каждом словаре хешируется только один раз.

Другие вопросы по теме