简体   繁体   English

获取独特的列表 <T> 通过列表TX的U属性?

[英]Get distinct List<T> by properties of U of the list T.X?

Given the following the following code. 给出以下代码。

class T { 
    public List<U> X { get; set; } /*.....*/ 
}
class U { 
    public int A { get; set; }
    public int B { get; set; } 
    // other properties omit for easier testing
}

var l = new List<T> {
  new T { X = new List<U> { new U { A = 0, B = 9 }, new U { A = 1, B = 8 } } },
  new T { X = new List<U> { new U { A = 0, B = 9 }, new U { A = 1, B = 8 } } },
  new T { X = new List<U> { new U { A = 2, B = 4 }, new U { A = 3, B = 5 } } },
  new T { X = new List<U> { new U { A = 2, B = 4 }, new U { A = 3, B = 5 } } },
  // ......
};

What's the most concise way to get the distinct List<T> of the l ? 获取l的唯一List<T>的最简洁方法是什么? The return is expected to have two sub-lists which X has [{0,9}, {1,8}] and [{2,4}, {3,5}]. 期望返回包含两个子列表,其中X具有[{0,9},{1,8}]和[{2,4},{3,5}]。


Updated code based on comments to Enigmativity's answer: 根据对谜题答案的注释更新了代码:

interface IBase<I> { I A { get; set; } I B { get; set; } }
class T<I> { 
    public List<U<I>> X { get; set; } /*.....*/ 
}
class U<I> : IBase<I> { 
    public I A { get; set; }
    public I B { get; set; } 
    // other properties omit for easier testing
}

var l = new List<T<int>> {
  new T<int> { X = new List<U<int>> { new U<int> { A=0, B=9 }, new U<int> { A=1, B=8 } } },
  new T<int> { X = new List<U<int>> { new U<int> { A=0, B=9 }, new U<int> { A=1, B=8 } } },
  new T<int> { X = new List<U<int>> { new U<int> { A=2, B=4 }, new U<int> { A=3, B=5 } } },
  new T<int> { X = new List<U<int>> { new U<int> { A=2, B=4 }, new U<int> { A=3, B=5 } } },
  // ......
};

Updated sample data as per comments: 根据注释更新了示例数据:

var l = new List<T> {
  new T { X = new List<U> { new U { A = 0, B = 9 }, new U { A = 1, B = 8 } } },
  new T { X = new List<U> { new U { A = 0, B = 9 }, new U { A = 1, B = 8 } } },
  new T { X = new List<U> { new U { A = 2, B = 4 }, new U { A = 3, B = 5 } } },
  new T { X = new List<U> { new U { A = 2, B = 4 }, new U { A = 3, B = 5 } } },
  new T { X = new List<U> {} }
  // ......
};

For your given code the quickest way is to implement an IEqualityComparer<T> and use that in the standard LINQ .Distinct operator. 对于给定的代码,最快的方法是实现IEqualityComparer<T>并将其用于标准LINQ .Distinct运算符。

public class TEqualityComparer : IEqualityComparer<T>
{
    public bool Equals(T t1, T t2)
    {
        if (t2 == null && t1 == null)
            return true;
        else if (t1 == null || t2 == null)
            return false;
        else
        {
            return
                t1.X.Select(x => x.A).SequenceEqual(t2.X.Select(x => x.A))
                && t1.X.Select(x => x.B).SequenceEqual(t2.X.Select(x => x.B));
        }
    }

    public int GetHashCode(T t)
    {
        return t.X.Select(x => x.A.GetHashCode())
            .Concat(t.X.Select(x => x.B.GetHashCode()))
            .Aggregate((x1, x2) => (x1 * 17 + 13) ^ x2);
    }
}

Then you can do this: 然后,您可以执行以下操作:

IEnumerable<T> result = l.Distinct(new TEqualityComparer());

Which gives you: 这给你:

结果

But you want the result as a List<List<U>> so then you'd do this: 但是您希望将结果作为List<List<U>>因此您可以这样做:

List<List<U>> result =
    l.Distinct(new TEqualityComparer())
        .Select(t => t.X.ToList())
        .ToList();

Based on your updated code, this is what you need: 根据您更新的代码,这是您需要的:

public class TEqualityComparer<V> : IEqualityComparer<T<V>>
{
    public bool Equals(T<V> t1, T<V> t2)
    {
        if (t2 == null && t1 == null)
            return true;
        else if (t1 == null || t2 == null)
            return false;
        else
        {
            return
                t1.X.Select(x => x.A).SequenceEqual(t2.X.Select(x => x.A))
                && t1.X.Select(x => x.B).SequenceEqual(t2.X.Select(x => x.B));
        }
    }

    public int GetHashCode(T<V> t)
    {
        return t.X.Select(x => x.A.GetHashCode())
            .Concat(t.X.Select(x => x.B.GetHashCode()))
            .Aggregate((x1, x2) => (x1 * 17 + 13) ^ x2);
    }
}

You'd call it like: 您可以这样称呼它:

IEnumerable<T<int>> result = l.Distinct(new TEqualityComparer<int>());

...or: ...要么:

List<List<U<int>>> result =
    l.Distinct(new TEqualityComparer<int>())
        .Select(t => t.X.ToList())
        .ToList();

With the updated data all you need to do to make this work now is to change GetHashCode to this: 使用更新的数据,现在要做的就是将GetHashCode更改为此:

public int GetHashCode(T<V> t)
{
    return t.X.Select(x => x.A.GetHashCode())
        .Concat(t.X.Select(x => x.B.GetHashCode()))
        .DefaultIfEmpty(0)
        .Aggregate((x1, x2) => (x1 * 17 + 13) ^ x2);
}

The data you added was for the old classes. 您添加的数据是针对旧类的。 I updated it to this: 我将其更新为:

var l = new List<T<int>> {
  new T<int> { X = new List<U<int>> { new U<int> { A=0, B=9 }, new U<int> { A=1, B=8 } } },
  new T<int> { X = new List<U<int>> { new U<int> { A=0, B=9 }, new U<int> { A=1, B=8 } } },
  new T<int> { X = new List<U<int>> { new U<int> { A=2, B=4 }, new U<int> { A=3, B=5 } } },
  new T<int> { X = new List<U<int>> { new U<int> { A=2, B=4 }, new U<int> { A=3, B=5 } } },
  new T<int> { X = new List<U<int>> { } },
  // ......
};

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

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