通过列表T.X的U属性获取不同的List <t>?

时间:2016-02-22 22:51:16

标签: c#

给出以下代码。

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 } } },
  // ......
};

获得List<T>的独特l的最简洁方法是什么?预计回报将有两个子列表X具有[{0,9},{1,8}]和[{2,4},{3,5}]。

根据对Enigmativity的回答的评论更新了代码:

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 } } },
  // ......
};

根据评论更新了样本数据:

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> {} }
  // ......
};

1 个答案:

答案 0 :(得分:3)

对于您给定的代码,最快的方法是实现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);
    }
}

然后你可以这样做:

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

这给了你:

result

但是你希望结果为List<List<U>>,那么你就这样做了:

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

根据您更新的代码,这就是您所需要的:

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

你会这样称呼:

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

...或:

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

使用更新的数据,您现在需要做的就是将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);
}

您添加的数据适用于旧类。我将其更新为:

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>> { } },
  // ......
};