【问题标题】:How to distinct for a list of list using LINQ?如何区分使用 LINQ 的列表列表?
【发布时间】:2020-02-26 17:31:36
【问题描述】:

在我的情况下,我有一个点列表,我想使用 linq 丢弃重复点的列表,其方式与 distinct 通常在项目列表中的工作方式类似。

我该怎么做? 这是一个代码 sn-p 可以更好地理解我的问题

var points = List<List<Point>>();

public struct Point: IEquatable<Point>
{

        public Point(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }


        public int X { get; }
        public int Y { get; }
}

谢谢

【问题讨论】:

  • 嗯,你需要实际实现IEquatable&lt;T&gt; 接口..?
  • 为什么你的观点包含一个列表?
  • “我想丢弃重复点的列表” 这是阴暗的解释。你的意思是一个独特的点列表?你的意思是唯一的点列表?
  • 尝试以下操作: public Boolean Equals(Point other) { return (this.X == other.X) && (this.Y == other.Y); }
  • 我建议添加一些带有预期输出的示例输入,以使您的问题更加清晰。

标签: c# list linq distinct


【解决方案1】:

首先,实际实现IEquatable:

public struct Point: IEquatable<Point> {

    public Point(int x, int y) {
        this.X = x;
        this.Y = y;
    }

    public int X { get; }
    public int Y { get; }

    public bool Equals (Point other) => 
        this.X == other.X && this.Y == other.Y;

}

然后创建一个自定义相等比较器。这需要一个相等逻辑和一个哈希码生成器。对于相等逻辑,请使用 SequenceEqual,对于哈希码生成器,您将不得不使用它,但 here's 是 Jon Skeet 的示例。我在下面使用了他的部分逻辑:

class ListPointComparer : IEqualityComparer<List<Point>> {

    public bool Equals(List<Point> a, List<Point> b) => a.SequenceEqual(b);

    public int GetHashCode(List<Point> list) {
        int hash = 19;
        foreach(var point in list)
            hash = hash * 31 + point.GetHashCode();
        return hash;
    }

}

现在想象这样的点:

var pointsA = new List<Point> { new Point (1,1), new Point(2,2) };
var pointsB = new List<Point> { new Point (1,1), new Point(2,2) };
var pointsC = new List<Point> { new Point (3,3), new Point(4,4) };
var pointLists = new List<List<Point>> { pointsA, pointsB, pointsC };   

使用您的比较器类:

var results = pointLists.Distinct(new ListPointComparer());
// Outputs only 2 lists, with pointsA and pointsB combined.

【讨论】:

    【解决方案2】:

    你可以使用HashSet这个类提供高性能的集合操作。集合是一个集合,它不包含重复的元素,并且其元素没有特定的顺序

    例子:

        public struct Point 
        {
            public HashSet<int> coordinateX;
            public HashSet<int> coordinateY;
    
            public Point(HashSet<int> a, HashSet<int> b) 
            {
                coordinateX = a;
                coordinateY = b;
            }
        }
        static void Main(string[] args)
        {
            var set1 = new HashSet<int>() { 2, 3, 4, 6, 8 };
            var set2 = new HashSet<int>() { 67, 31, 1, 3, 5 };
    
            var points = new List<List<Point>>();
    
            points.Add(new List<Point>() { new Point(set1, set2) });
    
            //TODO
        }
    

    【讨论】:

      【解决方案3】:

      如果你有这样的代码

      public class Point : IEquatable<Point>
      {
        public Point(int x, int y)
        {
          this.X = x;
          this.Y = y;
        }
      
        public int X { get; }
        public int Y { get; }
      
      
        public bool Equals(Point other)
        {
          //Check whether the compared object is null. 
          if (Object.ReferenceEquals(other, null)) return false;
      
          //Check whether the compared object references the same data. 
          if (Object.ReferenceEquals(this, other)) return true;
      
          //Check whether the products' properties are equal. 
          return X.Equals(other.X) && Y.Equals(other.Y);
        }
      
        // If Equals() returns true for a pair of objects  
        // then GetHashCode() must return the same value for these objects. 
      
        public override int GetHashCode()
        {
      
          //Get hash code for the Name field if it is not null. 
          int hashProductX = X == null ? 0 : X.GetHashCode();
      
          //Get hash code for the Code field. 
          int hashProductY = Y == null ? 0 : Y.GetHashCode();
      
          //Calculate the hash code for the product. 
          return hashProductX ^ hashProductY;
        }
      }
      

      那么这段代码就可以工作了

      var distinct_points = points.Distinct();
      

      假设点是这样定义的

      List<Point> points;
      

      你也可以使用

      var distinct_points = points.SelectMany(x => x).Distinct();
      

      如果点是这样定义的

      var points = List<List<Point>>();
      

      此示例改编自 https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.distinct?view=netframework-4.8 的文档

      【讨论】:

      • 我相信 OP 希望对 List&lt;List&lt;Point&gt;&gt; 使用 Distinct,而不仅仅是 List&lt;Point&gt;
      【解决方案4】:

      Linq Distinct 可以使用IEqualityComparer&lt;&gt;

      您可以实现一个实现该接口的新类,然后生成不同的列表。

      这是实现IEquatable&lt;&gt;、实现IEqualityComparer&lt;&gt; 和Test 类的完全编码的Point 的实现。

      测试类在每个列表上都做了一个“简单”的区别。如果您需要更复杂的不同点,例如所有列表中的不同点,请发布您的功能要求,我可以看到我能做什么。

          public struct Point : IEquatable<Point>
      {
          public Point(int x, int y) : this()
          {
              X = x;
              Y = y;
          }
      
          public int X { get; set; }
          public int Y { get; set; }
      
          public bool Equals(Point other)
          {
              if (other.X == X && other.Y == Y)
                  return true;
      
              return false;
          }
      
          public override bool Equals(object obj)
          {
              if (obj != null && obj.GetType() == typeof(Point))
                  return Equals((Point)obj);
      
              return base.Equals(obj);
          }
      
          public override int GetHashCode()
          {
              return HashCode.Combine(X, Y);
          }
      
          public int GetHashCode(Point obj)
          {
              return obj.GetHashCode();
          }
      }
      
      public class PointComparer : IEqualityComparer<Point>
      {
          public bool Equals(Point x, Point y)
          {
              return x.Equals(y);
          }
      
          public int GetHashCode(Point obj)
          {
              return obj.GetHashCode();
          }
      }
      
      public class Tester
      {
          public static List<List<Point>> Dist(List<List<Point>> points)
          {
              var results = new List<List<Point>>();
              var comparer = new PointComparer();
      
              foreach (var lst in points)
              {
                  results.Add(lst.Distinct(comparer).ToList());
              }
      
              return results;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2014-04-11
        • 1970-01-01
        • 2020-08-06
        • 2010-09-29
        • 1970-01-01
        • 2011-04-15
        • 1970-01-01
        相关资源
        最近更新 更多