简体   繁体   English

获取c#中List <T>中的不同值列表

[英]Get list of distinct values in List<T> in c#

So, say I have something like the following: 所以,说我有以下内容:

public class Element
{
  public int ID;
  public int Type;
  public Properties prorerty;
  ...
}
and

List Elements = new List();

and I have a list of these: 我有一个列表:

 List Elements = new List(); 

What would be the cleanest way to get a list of all distinct values in the prorerty column in Element class? 在Element类的prorerty列中获取所有不同值的列表最简洁的方法是什么? I mean, I could iterate through the list and add all values that aren't duplicates to another list of strings, but this seems dirty and inefficient. 我的意思是,我可以遍历列表并将所有不重复的值添加到另一个字符串列表中,但这看起来很脏且效率低下。 I have a feeling there's some magical Linq construction that'll do this in one line, but I haven't been able to come up with anything. 我有一种感觉,有一些神奇的Linq结构可以在一条线上做到这一点,但我无法想出任何东西。

 var results = Elements.Distinct();

Note: you will have to override .Equals and .GetHashCode() 注意:您必须覆盖.Equals.GetHashCode()

public class Element : IEqualityComparer<Element>
{
   public bool Equals(Element x, Element y)
   {
     if (x.ID == y.ID)
     {
        return true;
     }
     else
     {
        return false;
     }
   }
}

public int GetHashCode(Element obj)
{
    return obj.ID.GetHashCode();
}
var props = Elements.Select(x => x.Properties).Distinct();

And make sure you overridden .Equals() and .GetHashCode() methods. 并确保覆盖.Equals().GetHashCode()方法。
Or if you need direct strings from Properties : 或者如果您需要来自Properties直接字符串:

var props = Elements
    .Select(x => x.Properties != null ? x.Properties.Property : null)
    .Distinct();

If you need the string fields on the Properties field, and if you know the Properties field prorerty is never null , just use 如果您需要Properties字段中的字符串字段,并且如果您知道Properties字段prorerty永远不为null ,则只需使用

IEnumerable<string> uniqueStrings = Elements
  .Select(e => e.prorerty.Property).Distinct();

If there's a chance prorerty can be null, handle that situation in the lambda. 如果有一个机会prorerty可以为null,请在lambda中处理这种情况。

This will use the default equality comparer for String which is an ordinal comparison independent of culture and case-sensitive. 这将使用String的默认相等比较器,它是独立于文化和区分大小写的序数比较。

my working example from LINQPad (C# Program) 我从LINQPad(C#程序)的工作示例

void Main()
{
    var ret = new List<Element>();
    ret.Add(new Element(){ID=1});
    ret.Add(new Element(){ID=1});
    ret.Add(new Element(){ID=2});
    ret = ret.GroupBy(x=>x.ID).Select(x=>x.First()).ToList();
    Console.WriteLine(ret.Count()); // shows 2
}

public class Element
{
  public int ID;
  public int Type;
  public Properties prorerty; 
}

public class Properties
{
  public int Id;
  public string Property;

}

Isn't simpler to use one of the approaches shown below :) ? 使用下面显示的方法之一是不是更简单:)? You can just group your domain objects by some key and select FirstOrDefault like below. 您可以通过某个键对域对象进行分组,然后选择FirstOrDefault,如下所示。 This is a copy of my answer on similar question here: Get unique values - original answer 这是我在这里对类似问题的答案的副本: 获取独特的价值 - 原始答案

More interesting option is to create some Comparer adapter that takes you domain object and creates other object the Comparer can use/work with out of the box. 更有趣的选择是创建一些Comparer适配器,它接收域对象并创建Comparer可以使用/开箱即用的其他对象。 Base on the comparer you can create your custom linq extensions like in sample below. 基于比较器,您可以创建自定义linq扩展,如下面的示例所示。 Hope it helps :) 希望能帮助到你 :)

[TestMethod]
public void CustomDistinctTest()
{
    // Generate some sample of domain objects
    var listOfDomainObjects = Enumerable
                                .Range(10, 10)
                                .SelectMany(x => 
                                    Enumerable
                                    .Range(15, 10)
                                    .Select(y => new SomeClass { SomeText = x.ToString(), SomeInt = x + y }))
                                .ToList();

    var uniqueStringsByUsingGroupBy = listOfDomainObjects
                                    .GroupBy(x => x.SomeText)
                                    .Select(x => x.FirstOrDefault())
                                    .ToList();

    var uniqueStringsByCustomExtension = listOfDomainObjects.DistinctBy(x => x.SomeText).ToList();
    var uniqueIntsByCustomExtension = listOfDomainObjects.DistinctBy(x => x.SomeInt).ToList();

    var uniqueStrings = listOfDomainObjects
                            .Distinct(new EqualityComparerAdapter<SomeClass, string>(x => x.SomeText))
                            .OrderBy(x=>x.SomeText)
                            .ToList();

    var uniqueInts = listOfDomainObjects
                            .Distinct(new EqualityComparerAdapter<SomeClass, int>(x => x.SomeInt))
                            .OrderBy(x => x.SomeInt)
                            .ToList();
}

Custom comparer adapter: 自定义比较适配器:

public class EqualityComparerAdapter<T, V> : EqualityComparer<T>
    where V : IEquatable<V>
{
    private Func<T, V> _valueAdapter;

    public EqualityComparerAdapter(Func<T, V> valueAdapter)
    {
        _valueAdapter = valueAdapter;
    }

    public override bool Equals(T x, T y)
    {
        return _valueAdapter(x).Equals(_valueAdapter(y));
    }

    public override int GetHashCode(T obj)
    {
        return _valueAdapter(obj).GetHashCode();
    }
}

Custom linq extension (definition of DistinctBy extension method): 自定义linq扩展(DistinctBy扩展方法的定义):

// Embed this class in some specific custom namespace
public static class DistByExt
{
    public static IEnumerable<T> DistinctBy<T,V>(this IEnumerable<T> enumerator,Func<T,V> valueAdapter)
        where V : IEquatable<V>
    {
        return enumerator.Distinct(new EqualityComparerAdapter<T, V>(valueAdapter));
    }
}

Definition of domain class used in test case: 测试用例中使用的域类的定义:

public class SomeClass
{
    public string SomeText { get; set; }
    public int SomeInt { get; set; }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM