简体   繁体   中英

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. so...

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

C now has 1 and 3 in it.

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:

    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). 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.

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. I guess you could cheat and return a lambda that applies AsEnumerable() and then uses IEnumerable.WhereOther .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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