【问题标题】:Get list of distinct values in List<T> in c#获取 C# 中 List<T> 中不同值的列表
【发布时间】:2013-02-11 10:15:44
【问题描述】:

所以,假设我有以下内容:

public class Element
{
  public int ID;
  public int Type;
  public Properties prorerty;
  ...
}
public class Properties
{
  public int Id;
  public string Property;
  ...
}

我有一份清单:

List Elements = new List();

在 Element 类的 prorerty 列中获取所有不同值的列表的最简洁方法是什么?我的意思是,我可以遍历列表并将所有不重复的值添加到另一个字符串列表中,但这似乎很脏且效率低下。我有一种感觉,有一些神奇的 Linq 构造可以在一行中完成此操作,但我无法想出任何东西。

【问题讨论】:

标签: c# .net linq list distinct


【解决方案1】:
 var results = Elements.Distinct();

注意:您必须覆盖 .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();
}

【讨论】:

  • 或者传递一个自定义的IEqualityComparer。 :)
  • 对我来说听起来他只是想要一个字符串集合。为此,他可以为System.String 使用预定义的相等比较器。
  • 在 Element 中实现 IEqualityComparer&lt;Element&gt; 是很不寻常的。创建 ElementComparer 类或在 Element 中实现 IComparable&lt;Element&gt;
  • @Mykhalik - 这有帮助吗?如果有,请将其标记为答案。
【解决方案2】:

使用下面显示的方法之一不是更简单:) 吗?您可以通过某个键对域对象进行分组,然后选择 FirstOrDefault 如下所示。 这是我对类似问题的回答的副本: Get unique values - original answer

更有趣的选项是创建一些比较器适配器,该适配器将您带入域对象并创建比较器可以使用/开箱即用的其他对象。基于比较器,您可以创建自定义 linq 扩展,如下面的示例所示。希望对你有帮助:)

[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();
}

自定义比较器适配器:

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();
    }
}

自定义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));
    }
}

测试用例中使用的领域类的定义:

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

}

【讨论】:

  • GroupBy(x => x.SomeText).Select(x => x.FirstOrDefault()).ToList();为我解决了,谢谢!
【解决方案3】:
var props = Elements.Select(x => x.Properties).Distinct();

并确保覆盖 .Equals().GetHashCode() 方法。
或者,如果您需要来自Properties 的直接字符串:

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

【讨论】:

    【解决方案4】:

    如果您需要Properties 字段上的字符串字段,并且如果您知道Properties 字段prorerty 永远不会是null,只需使用

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

    如果prorerty 有可能为空,请在 lambda 中处理这种情况。

    这将使用String 的默认相等比较器,这是一个独立于文化和区分大小写的序数比较。

    【讨论】:

      【解决方案5】:

      我来自 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;
      
      }
      

      【讨论】:

        猜你喜欢
        • 2012-05-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-27
        • 2016-03-22
        • 1970-01-01
        • 2022-01-09
        • 1970-01-01
        相关资源
        最近更新 更多