使用LINQ将列表转换为字典,而不必担心重复

我有一个Person对象列表。 我想转换为一个字典,其中的关键是名和姓(连接),值是Person对象。

问题是我有一些重复的人,所以如果我使用这个代码,这将炸毁:

private Dictionary<string, Person> _people = new Dictionary<string, Person>(); _people = personList.ToDictionary( e => e.FirstandLastName, StringComparer.OrdinalIgnoreCase); 

我知道这听起来很奇怪,但我现在不太在乎重复的名字。 如果有多个名字,我只想抓住一个。 有没有反正我可以写上面的代码,所以它只是一个名字,不会炸毁重复?

这是一个显而易见的非LINQ解决scheme:

 foreach(var person in personList) { if(!myDictionary.Keys.Contains(person.FirstAndLastName)) myDictionary.Add(person.FirstAndLastName, person); } 

LINQ解决scheme:

 // Use the first value in group var _people = personList .GroupBy(p => p.FirstandLastName, StringComparer.OrdinalIgnoreCase) .ToDictionary(g => g.Key, g => g.First(), StringComparer.OrdinalIgnoreCase); // Use the last value in group var _people = personList .GroupBy(p => p.FirstandLastName, StringComparer.OrdinalIgnoreCase) .ToDictionary(g => g.Key, g => g.Last(), StringComparer.OrdinalIgnoreCase); 

如果你更喜欢非LINQ解决scheme,那么你可以这样做:

 // Use the first value in list var _people = new Dictionary<string, Person>(StringComparer.OrdinalIgnoreCase); foreach (var p in personList) { if (!_people.ContainsKey(p.FirstandLastName)) _people[p.FirstandLastName] = p; } // Use the last value in list var _people = new Dictionary<string, Person>(StringComparer.OrdinalIgnoreCase); foreach (var p in personList) { _people[p.FirstandLastName] = p; } 

使用Distinct()和不分组的Linq解决scheme是:

 var _people = personList .Select(item => new { Key = item.Key, FirstAndLastName = item.FirstAndLastName }) .Distinct() .ToDictionary(item => item.Key, item => item.FirstFirstAndLastName, StringComparer.OrdinalIgnoreCase); 

我不知道它是否比LukeH的解决scheme好,但它也可以。

这应该与lambdaexpression式一起工作:

 personList.Distinct().ToDictionary(i => i.FirstandLastName, i => i); 

为了消除重复,实现一个可以在Distinct()方法中使用的IEqualityComparer<Person> ,然后让你的字典变得容易。 鉴于:

 class PersonComparer : IEqualityComparer<Person> { public bool Equals(Person x, Person y) { return x.FirstAndLastName.Equals(y.FirstAndLastName, StringComparison.OrdinalIgnoreCase); } public int GetHashCode(Person obj) { return obj.FirstAndLastName.ToUpper().GetHashCode(); } } class Person { public string FirstAndLastName { get; set; } } 

获取你的字典:

 List<Person> people = new List<Person>() { new Person() { FirstAndLastName = "Bob Sanders" }, new Person() { FirstAndLastName = "Bob Sanders" }, new Person() { FirstAndLastName = "Jane Thomas" } }; Dictionary<string, Person> dictionary = people.Distinct(new PersonComparer()).ToDictionary(p => p.FirstAndLastName, p => p); 

您也可以使用ToLookup LINQ函数,然后您可以几乎与字典交换使用。

 _people = personList .ToLookup(e => e.FirstandLastName, StringComparer.OrdinalIgnoreCase); _people.ToDictionary(kl => kl.Key, kl => kl.First()); // Potentially unnecessary 

这将基本上在LukeH的回答中做GroupBy,但是会给Dictionary提供的散列。 所以,你可能不需要把它转换成字典,但是只要你需要访问键的值,就使用LINQ First函数。

您可以创build类似于ToDictionary()的扩展方法,区别在于它允许重复。 就像是:

  public static Dictionary<TKey, TElement> SafeToDictionary<TSource, TKey, TElement>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer = null) { var dictionary = new Dictionary<TKey, TElement>(comparer); if (source == null) { return dictionary; } foreach (TSource element in source) { dictionary[keySelector(element)] = elementSelector(element); } return dictionary; } 

在这种情况下,如果有重复,则最后一个值获胜。

  DataTable DT = new DataTable(); DT.Columns.Add("first", typeof(string)); DT.Columns.Add("second", typeof(string)); DT.Rows.Add("ss", "test1"); DT.Rows.Add("sss", "test2"); DT.Rows.Add("sys", "test3"); DT.Rows.Add("ss", "test4"); DT.Rows.Add("ss", "test5"); DT.Rows.Add("sts", "test6"); var dr = DT.AsEnumerable().GroupBy(S => S.Field<string>("first")).Select(S => S.First()). Select(S => new KeyValuePair<string, string>(S.Field<string>("first"), S.Field<string>("second"))). ToDictionary(S => S.Key, T => T.Value); foreach (var item in dr) { Console.WriteLine(item.Key + "-" + item.Value); } 

从Carra的解决scheme开始,你也可以把它写成:

 foreach(var person in personList.Where(el => !myDictionary.ContainsKey(el.FirstAndLastName))) { myDictionary.Add(person.FirstAndLastName, person); }