使用LINQ创建字典并避免“已添加相同键的项目”错误

时间:2015-07-20 15:01:17

标签: c# linq

我想在词典中找到一个键,如果找到了替换值,或者如果不是则添加键/值。

代码:

 Owner       Inventory   
 ---------   --------------
 Noemi          3                   Owner1:Noemi | Owner2:Noemi
 Carl           3                   Owner1:Carl | Owner2:Carl
 Darla          2                   Owner1:Darla| Owner2:null
 Paola          2                   Owner1:null| Owner2:Paola

LINQ解决方案(抛出public class MyObject { public string UniqueKey { get; set; } public string Field1 { get; set; } public string Field2 { get; set; } } ):

An item with the same key has already been added.

ForEach解决方案(有效):

Dictionary<string, MyObject> objectDict = csvEntries.ToDictionary(csvEntry => csvEntry.ToMyObject().UniqueKey, csvEntry => csvEntry.ToMyObject());

我真的很喜欢LINQ解决方案,但就其而言,它会引发上述错误。有没有什么好方法可以避免错误并使用LINQ?

2 个答案:

答案 0 :(得分:14)

您可以使用GroupBy创建唯一键:

Dictionary<string, MyObject> objectDict = csvEntries
    .Select(csvEntry => csvEntry.ToMyObject())
    .GroupBy(x => x.UniqueKey)
    .ToDictionary(grp => grp.Key, grp => grp.First());

但是,您可以使用grp.First()ToList创建一个集合,而不是ToArray。在这种情况下,如果密钥重复,则不会使用任意对象。

另一种选择是使用Lookup<TKey, TValue>允许重复键甚至是不存在的键,在这种情况下你得到一个空序列。

var uniqueKeyLookup = csvEntries
    .Select(csvEntry => csvEntry.ToMyObject())
    .ToLookup(x => x.UniqueKey);
IEnumerable<MyObject> objectsFor1234 = uniqueKeyLookup["1234"]; // empty if it doesn't exist

答案 1 :(得分:1)

基于Rango的答案,这是您可以使用的扩展方法,因此您无需在整个项目中重复实现:

NOTICE: found : f NOTICE: payment_method (,,,,,,,,,,,,) 

默认情况下,当有重复项时,它将选择第一个元素,但是我提供了一个可选参数,您可以在其中指定备用选择器。调用扩展方法的示例:

public static class DictionaryExtensions
{
    public static Dictionary<TKey, TValue> ToDictionaryWithDupSelector<TKey, TValue>(
        this IEnumerable<TValue> enumerable,
        Func<TValue, TKey> groupBy, Func<IEnumerable<TValue>, TValue> selector = null) {

        if (selector == null)
            selector = new Func<IEnumerable<TValue>, TValue>(grp => grp.First());

        return enumerable
            .GroupBy(e => groupBy(e))
            .ToDictionary(grp => grp.Key, grp => selector(grp));
    }
}