Как отличить список списка с помощью LINQ? - PullRequest
0 голосов
/ 26 февраля 2020

в моем случае у меня есть список списков точек, которые я хочу отбросить списки дубликатов точек, используя 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; }
}

Спасибо

Ответы [ 4 ]

2 голосов
/ 26 февраля 2020

Во-первых, на самом деле реализуем 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;

}

Затем создайте пользовательский компаратор равенства. Это требует логики равенства c и генератора кода ha sh. Для логики равенства c используйте SequenceEqual, для генератора кода ha sh вам придется поиграться с ним, но вот пример через Jon Skeet. Я использовал часть его логики c ниже:

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.
1 голос
/ 26 февраля 2020

Вы можете использовать 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
    }
0 голосов
/ 26 февраля 2020

Linq Distinct может использовать IEqualityComparer<>

. Вы можете реализовать новый класс, реализующий этот интерфейс, и затем генерировать отдельные списки.

Вот реализация полностью закодированного Point, реализующего IEquatable<> и реализовано IEqualityComparer<> и тестовый класс.

Тестовый класс делает «простые» отличия в каждом списке. Если вам нужны более сложные отличия, такие как отличительные точки во всех списках, опубликуйте свои функциональные требования, и я пойму, что я могу сделать.

    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;
    }
}
0 голосов
/ 26 февраля 2020

Если у вас есть код, подобный этому

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

...