0

我是 Linq 的新手,我正在尝试根据一个字段从两个列表中过滤记录。每个列表都有一个 ID,我想获取 ID 出现在一个列表中而不是另一个列表中的任何记录。我只需要一个 ID 列表就可以做到这一点,如下所示:

List1 = _class1.getList1();
List2 = _class2.getList2();

(出于介绍目的,我正在使用一个我想摆脱的类,它有一个数据列表和一个只有 ID 的列表,我应该能够只用数据列表来做到这一点,尽管在两个语句中比较list1 到 list2,反之亦然)

var inList1ButNot2 = List1.IDList.Except(List2.IDList);
var inList2ButNot1 = List2.IDList.Except(List1.IDList);

我遇到麻烦的地方是使用数据列表来比较第二个列表的 ID 字段。我相信它应该是这样的:

var inList1ButNot2 = DataList1.Select(x => x.ID)
        .Except(DataList2.Select(y => y.ID));

问题是我没有得到整个记录只是我正在比较的字段,我是否需要在之后单独选择每个字段,或者如果 ID 出现在一个列表中但没有出现在语句中,是否有办法选择记录另一个?

4

6 回答 6

3

所以你真正想要的是一种ExceptBy方法;您希望能够Except在每个元素的投影上执行,而不是在元素本身上执行。这是这种方法的一个实现:

public static IEnumerable<TSource> ExceptBy<TSource, TKey>(
    this IEnumerable<TSource> source,
    IEnumerable<TSource> other,
    Func<TSource, TKey> selector,
    IEqualityComparer<TKey> comparer = null)
{
    comparer = comparer ?? EqualityComparer<TKey>.Default;

    var set = new HashSet<TKey>(other.Select(selector), comparer);

    foreach (var item in source)
        if (set.Add(selector(item)))
            yield return item;
}

现在你可以这样做:

var inList1ButNot2 = DataList1.ExceptBy(DataList2, item => item.ID);
var inList2ButNot1 = DataList2.ExceptBy(DataList1, item => item.ID);
于 2013-06-27T14:31:35.150 回答
2

可能有更好的方法来做到这一点,但是:

var inList1ButNot2 = DataList1.Where(x => !(DataList2.Any(y => y.ID == x.ID)));

注意:我是徒手写的,所以可能有错字。

于 2013-06-27T14:31:19.443 回答
0
        var list1 = new List<Asd>();
        var list2 = new List<Asd>();

        var asd = new Asd() {Id = 1, Name = "asd"};
        var asd2 = new Asd() {Id = 2, Name = "asd"};
        var asd3 = new Asd() {Id = 3, Name = "asd"};
        var asd4 = new Asd() {Id = 4, Name = "asd"};
        var asd5 = new Asd() {Id = 5, Name = "asd"};

        list1.Add(asd);
        list1.Add(asd2);
        list1.Add(asd3);

        list2.Add(asd);
        list2.Add(asd4);
        list2.Add(asd5);

        var onlyInFirstList = list1.Where(x => !list2.Any(y => y == x));
        var onlyInSecondList = list2.Where(x => !list1.Any(y => y == x));

这应该有效,但不完美但有效:)

于 2013-06-27T14:29:47.930 回答
0

你可能会尝试这样的事情。

public void Test(List<List1> list1, List<List2> list2)
{
    var result = from l1 in list1
                 where list2.All(l2 => l1.Id != l2.Id)
                 select l1;

}

或者,如果你有来自两者的属性(我假设它们是不同的类型?)你可以返回一个匿名类型并从调用者实例中带回属性

public void Test(List<List1> list1, List<List2> list2)
{
    var result = from l1 in list1
                 where list2.All(l2 => l1.Id != l2.Id)
                 select new
                 {
                     l1.Id,
                     l1.OtherField1,
                     Test = 10.5, //Example declare new field
                     SomethingElse = this.PropertyXyz; //Set new field = instance property
                 };

}
于 2013-06-27T14:34:24.637 回答
0

与其重写Except(以及所有其他集合操作)中的逻辑,而是允许可以为其他类和选择器重用的东西,考虑如下内容:

private class LambdaComparer<T, U> : IEqualityComparer<T>
{
    private Func<T, U> selector;

    public LambdaComparer(Func<T, U> selector)
    {
        this.selector = selector;
    }

    public bool Equals(T x, T y)
    {
        if (x == null && y == null) return true;
        if (x == null || y == null) return false;
        return EqualityComparer<U>.Default.Equals(selector(x), selector(y));
    }

    public int GetHashCode(T obj)
    {
        if (obj == null) return 0;
        return EqualityComparer<U>.Default.GetHashCode(selector(obj));
    }
}

var inList1ButNot2 = List1.IDList.Except(
    List2.IDList,
    new LambdaComparer<ClassWithID, int>(w => w.ID));
于 2013-06-27T14:46:35.077 回答
-1

你可以试试这样的

list1 = list1.Union(list2).Distinct().ToList();
于 2013-06-27T14:46:03.033 回答