Я не могу понять, как сохранить ключи и значения в словаре, когда пытаюсь объединить два словаря. Я продолжаю получать 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());
}
Но я продолжаю получать.
не может быть выведено из использования. Попробуйте указать аргументы типа явно.
Я хочу избежать получения всех ключей и всех значений в отдельных списках, которые я позже просматриваю, чтобы добавить ключ и значение в новый словарь.
Если вы получаете исключение из-за повторяющихся ключей, то похоже, что у вас есть дубликаты ключей!
Вы проверили два словаря, прежде чем пытаться их объединить? Простой вызов =+ 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;
}
В самом деле? покажи лучше...
Решение Габриэля Станку значительно эффективнее вашего подхода ToLookup
+ToDictionary
.
Подход «без LINQ», вероятно, можно было бы дополнительно оптимизировать с помощью метода CollectionsMarshal.GetValueRefOrAddDefault (.NET 6).
наверное да, пожалуйста напишите ответ
Вот решение, основанное на 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>
в каждом словаре хешируется только один раз.
Простой, но довольно неэффективный.