从IEnumerable中过滤重复项

new*_*mem 19 c#

我有这个代码:

class MyObj {
    int Id;
    string Name;
    string Location;
}

IEnumerable<MyObj> list;
Run Code Online (Sandbox Code Playgroud)

我想将列表转换为这样的字典:

list.ToDictionary(x => x.Name);
Run Code Online (Sandbox Code Playgroud)

但它告诉我我有重复的密钥.如何只保留每个键的第一项?

Jor*_*ren 22

我想最简单的方法是按键分组并获取每个组的第一个元素:

list.GroupBy(x => x.name).Select(g => g.First()).ToDictionary(x => x.name);
Run Code Online (Sandbox Code Playgroud)

或者您可以使用,Distinct如果您的对象实现IEquatable按键比较它们之间:

// I'll just randomly call your object Person for this example.
class Person : IEquatable<Person> 
{
    public string Name { get; set; }

    public bool Equals(Person other)
    {
        if (other == null)
            return false;

        return Name == other.Name;
    }

    public override bool Equals(object obj)
    {
        return base.Equals(obj as Person);
    }

    public override int GetHashCode()
    {
        return Name.GetHashCode();
    }
}

...

list.Distinct().ToDictionary(x => x.Name);
Run Code Online (Sandbox Code Playgroud)

或者,如果您不想这样做(可能因为您通常希望以不同的方式比较相等性,因此Equals已经在使用中),您可以IEqualityComparer为此情况进行自定义实现:

class PersonComparer : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {
        if (x == null)
            return y == null;

        if (y == null)
            return false;

        return x.Name == y.Name;
    }

    public int GetHashCode(Person obj)
    {
        return obj.Name.GetHashCode();
    }
}

...

list.Distinct(new PersonComparer()).ToDictionary(x => x.Name);
Run Code Online (Sandbox Code Playgroud)


noc*_*ura 5

list.Distinct().ToDictionary(x => x.Name);
Run Code Online (Sandbox Code Playgroud)


Ric*_*lay 5

您还可以创建自己的 Distinct 扩展重载方法,该方法接受 Func<> 以选择不同的键:

public static class EnumerationExtensions
{
    public static IEnumerable<TSource> Distinct<TSource,TKey>(
        this IEnumerable<TSource> source, Func<TSource,TKey> keySelector)
    {
        KeyComparer comparer = new KeyComparer(keySelector);

        return source.Distinct(comparer);
    }

    private class KeyComparer<TSource,TKey> : IEqualityComparer<TSource>
    {
        private Func<TSource,TKey> keySelector;

        public DelegatedComparer(Func<TSource,TKey> keySelector)
        {
            this.keySelector = keySelector;
        }

        bool IEqualityComparer.Equals(TSource a, TSource b)
        {
            if (a == null && b == null) return true;
            if (a == null || b == null) return false;

            return keySelector(a) == keySelector(b);
        }

        int IEqualityComparer.GetHashCode(TSource obj)
        {
            return keySelector(obj).GetHashCode();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

对任何错误的代码格式表示歉意,我想减少页面上代码的大小。无论如何,您可以使用 ToDictionary:

 var dictionary = list.Distinct(x => x.Name).ToDictionary(x => x.Name);
Run Code Online (Sandbox Code Playgroud)