如何使用 LINQ 区分列表列表?
How to distinct for a list of list using LINQ?
在我的例子中,我有一个点列表,我想使用 linq 丢弃重复点列表,其方式与项目列表中不同项通常的工作方式类似。
我该怎么做?
这是一个代码片段,可以更好地理解我的问题
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; }
}
谢谢
如果你有这样的代码
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>>();
documentation this example was adapted from https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.distinct?view=netframework-4.8
首先,实际实现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 };
使用你的比较器 class:
var results = pointLists.Distinct(new ListPointComparer());
// Outputs only 2 lists, with pointsA and pointsB combined.
Linq Distinct 可以使用 IEqualityComparer<>
您可以实现一个新的 class 实现该接口,然后生成不同的列表。
这里是一个完全编码点的实现,实现了 IEquatable<>
,并实现了 IEqualityComparer<>
和测试 class。
测试 class 在每个列表上执行 'simple' 不同。如果您需要更复杂的不同点,例如所有列表中的不同点,post 您的功能要求,我知道我能做什么。
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;
}
}
你可以使用HashSet这个class提供高性能的集合操作。集合是一个不包含重复元素的集合,其元素没有特定的顺序
示例:
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
}
在我的例子中,我有一个点列表,我想使用 linq 丢弃重复点列表,其方式与项目列表中不同项通常的工作方式类似。
我该怎么做? 这是一个代码片段,可以更好地理解我的问题
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; }
}
谢谢
如果你有这样的代码
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>>();
documentation this example was adapted from https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.distinct?view=netframework-4.8
首先,实际实现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 };
使用你的比较器 class:
var results = pointLists.Distinct(new ListPointComparer());
// Outputs only 2 lists, with pointsA and pointsB combined.
Linq Distinct 可以使用 IEqualityComparer<>
您可以实现一个新的 class 实现该接口,然后生成不同的列表。
这里是一个完全编码点的实现,实现了 IEquatable<>
,并实现了 IEqualityComparer<>
和测试 class。
测试 class 在每个列表上执行 'simple' 不同。如果您需要更复杂的不同点,例如所有列表中的不同点,post 您的功能要求,我知道我能做什么。
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;
}
}
你可以使用HashSet这个class提供高性能的集合操作。集合是一个不包含重复元素的集合,其元素没有特定的顺序
示例:
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
}