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

leo*_*ora 145 c# linq dictionary

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

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

private Dictionary<string, Person> _people = new Dictionary<string, Person>();

_people = personList.ToDictionary(
    e => e.FirstandLastName,
    StringComparer.OrdinalIgnoreCase);
Run Code Online (Sandbox Code Playgroud)

我知道这听起来很奇怪,但我现在并不关心重复的名字.如果有多个名字我只想抓一个.无论如何,我可以在上面写这个代码,所以它只需要一个名字,并没有炸毁重复?

Luk*_*keH 392

LINQ解决方案:

// 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);
Run Code Online (Sandbox Code Playgroud)

如果您更喜欢非LINQ解决方案,那么您可以执行以下操作:

// 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;
}
Run Code Online (Sandbox Code Playgroud)

  • @LukeH次要注意:你的两个片段不等同:LINQ变体保留第一个元素,非LINQ片段保留最后一个元素? (6认同)
  • @toong:这是真的,绝对值得注意.(虽然在这种情况下,OP似乎并不关心他们最终会使用哪个元素.) (4认同)
  • +1非常优雅(我将尽快投票-今天不再有投票:)) (2认同)

Car*_*rra 66

这是明显的非linq解决方案:

foreach(var person in personList)
{
  if(!myDictionary.Keys.Contains(person.FirstAndLastName))
    myDictionary.Add(person.FirstAndLastName, person);
}
Run Code Online (Sandbox Code Playgroud)

  • 多数民众赞成2007年:) (189认同)
  • 或者使用会忽略大小写的StringComparer创建字典,如果这就是你需要的,那么你的添加/检查代码并不关心你是否忽略大小写. (11认同)
  • 这不会忽视案例 (3认同)

Til*_*ito 38

使用Distinct()并且没有分组的Linq解决方案是:

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

我不知道它是否比LukeH的解决方案更好,但它也可以.

  • 忽略我以前的评论.请参阅http://stackoverflow.com/questions/543482/linq-select-distinct-with-anonymous-types (5认同)

Ank*_*ass 29

这应该适用于lambda表达式:

personList.Distinct().ToDictionary(i => i.FirstandLastName, i => i);
Run Code Online (Sandbox Code Playgroud)

  • 这仅在Person类的默认IEqualityComparer按名字和姓氏进行比较时才有效,忽略大小写.否则编写这样的IEqualityComparer并使用相关的Distinct重载.此外,您的ToDIctionary方法应采用不区分大小写的比较器来匹配OP的要求. (3认同)
  • 它必须是:`personList.Distinct().ToDictionary(i => i.FirstandLastName,i => i);` (2认同)

pal*_*wim 11

您还可以使用ToLookupLINQ函数,然后您可以将它与字典几乎互换使用.

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

这将基本上在LukeH的答案中进行GroupBy ,但是会给出Dictionary提供的散列.因此,您可能不需要将其转换为Dictionary,而只需First在需要访问键的值时使用LINQ 函数.


Ant*_*ram 7

要处理消除重复项,请实现IEqualityComparer<Person>可在Distinct()方法中使用的方法,然后轻松获取字典.鉴于:

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; }
}
Run Code Online (Sandbox Code Playgroud)

获取你的字典:

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);
Run Code Online (Sandbox Code Playgroud)


Eri*_*ric 6

您可以创建类似于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; 
    }
Run Code Online (Sandbox Code Playgroud)

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

  • 我不敢相信这个答案不是得票最多的答案。`ToLookup`、`Distinct` 等都会对性能产生可怕的影响。AFAICT 是唯一一个与原始“ToDictionary”执行速度大致相同的选项 (2认同)