简体   繁体   English

使用linq使用另一个条件删除一个列表中的元素

[英]Use linq to remove elements in one list using a condition in another

I have 我有

List<X> A = new List<X>{null,"1",null,"3"};
List<Y> B = new List<Y>{  0 , 1 ,  2 , 3 };

I want to use linq to list only the elemnts in B that have a corresponding value in A that is not null. 我想使用linq仅列出B中具有不为null的对应值的elemnt。 so... 所以...

List<Y> C = [some linq expression using A and B];

C now has 1 and 3 in it. C现在有1和3。

How can this be done? 如何才能做到这一点?

List<String> A = new List<String> { null, "1", null, "3" };
List<int> B = new List<int> { 0, 1, 2, 3 };

var C = A.Zip(B, (s, n) => new { a = s, b = n })
         .Where(x => x.a != null)
         .Select(x => x.b)
         .ToList();
var c = B.Where((o, i) => A[i] != null).ToList();

Edit to note that it was unclear to me when this was written that both lists are aligned by index. 编辑以注意,在撰写本文时,尚不清楚两个列表均按索引对齐。 Unsure of the value of this response given that information. 给定该信息,不确定该响应的值。 It's certainly less valuable than I initially imagined. 它肯定没有我最初想象的有价值。

Essentially what you want is an intersection. 本质上,您想要的是一个十字路口。 Here's an answer using Intersect() that works based on the data and parameters supplied in your example: 这是使用Intersect()的答案,该答案基于示例中提供的数据和参数:

    var a = new List<string> { null, "1", null, "3" };
    var b = new List<int> { 0, 1, 2, 3 };
    var intersection = a.Intersect(b.Select(x => x.ToString())).ToList();

You should be able to adapt to an intersection that works for you. 您应该能够适应适合您的交叉路口。

If both of your lists really have nullable items in them, then you'll need additional null checks on the b list (I'm just blindly calling ToString() on each item in it). 如果您的两个列表中确实都包含可为空的项目,那么您将需要在b列表上进行其他空检查(我只是在其中的每个项目上盲目地调用ToString())。 But there's no reason to filter out nulls in A if B contains no nulls and you are doing an intersection, they will be filtered out as part of that process. 但是,如果B中不包含空值并且您正在做交集,则没有理由在A中过滤出空值,作为该过程的一部分,它们将被过滤掉。

Consider also that: 还请考虑:

    b.Select(x => x.ToString()) ...

Could very easily be: 可能很容易是:

    b.Select(x => ConvertTypeBToTypeA(x)) ...
List<string> A = new List<string> { null, "1", null, "3" };
List<int> B = new List<int> { 0, 1, 2, 3 };

var C = B.Where(x => A.Contains(x.ToString()));

try this: 尝试这个:

var c = Enumerable.Range(0, Math.Min(B.Count, A.Count))
                  .Where(i => A[i] != null)
                  .Select(i => B[i]).ToList();

How about an extension method to avoid some overhead? 扩展方法如何避免一些开销?

public static class Ext {
    public static IEnumerable<T1> WhereOther<T1, T2>(this IEnumerable<T1> src, IEnumerable<T2> filter, Func<T2, bool> pred) {
        using (var isrc = src.GetEnumerator())
        using (var ifilter = filter.GetEnumerator())
            while (ifilter.MoveNext())
                if (isrc.MoveNext())
                    if (pred(ifilter.Current))
                        yield return isrc.Current;

    }
}

With that created, you can use 创建完成后,您可以使用

var ans = B.WhereOther(A, p => p != null);

You may also want an IQueryable variant, though creating one isn't that easy. 您可能还需要一个IQueryable变体,尽管创建变体并不是那么容易。 I guess you could cheat and return a lambda that applies AsEnumerable() and then uses IEnumerable.WhereOther . 我猜你可以作弊并返回一个应用AsEnumerable()然后使用IEnumerable.WhereOther的lambda。

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

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