Rich Oliver
Rich Oliver

Reputation: 6109

c# Find an item in 2 / multiple lists

I have the presumably common problem of having elements that I wish to place in 2 (or more) lists. However sometimes I want to find an element that could be in one of the lists. Now there is more than one way of doing this eg using linq or appending, but all seem to involve the unnecessary creation of an extra list containing all the elements of the separate lists and hence waste processing time.

So I was considering creating my own generic FindinLists class which would take 2 lists as its constructor parameters would provide a Find() and an Exists() methods. The Find and Exists methods would only need to search the second or subsequent lists if the item was not found in the first list. The FindInLists class could be instantiated in the getter of a ( no setter)property. A second constructor for the FindInLists class could take an array of lists as its parameter.

Is this useful or is there already a way to search multiple lists without incurring the wasteful overhead of the creation of a super list?

Upvotes: 2

Views: 4271

Answers (5)

voidengine
voidengine

Reputation: 2579

I believe IEnumerable<T>.Concat() is what you need. It doesn't create an extra list, it only iterates through the given pair of collections when queried

Concat() uses deferred execution, so at the time it's called it only creates an iterator which stores the reference to both concatenated IEnumerables. At the time the resulting collection is enumerated, it iterates through first and then through the second. Here's the decompiled code for the iterator - no rocket science going on there:

private static IEnumerable<TSource> ConcatIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second)
{
    foreach (TSource iteratorVariable0 in first)
    {
        yield return iteratorVariable0;
    }
    foreach (TSource iteratorVariable1 in second)
    {
        yield return iteratorVariable1;
    }
}

When looking to the docs for Concat(), I've stumbled across another alternative I didn't know - SelectMany. Given a collection of collections it allows you to work with the children of all parent collections at once like this:

IEnumerable<string> concatenated = new[] { firstColl, secondColl }
    .SelectMany(item => item);

Upvotes: 2

Rich O&#39;Kelly
Rich O&#39;Kelly

Reputation: 41757

Linq already has this functionality by virtue of the FirstOrDefault method. It uses deferred execution so will stream from any input and will short circuit the return when a matching element is found.

var matched = list1.Concat(list2).FirstOrDefault(e => element.Equals(e));

Update

BaseType matched = list1.Concat(list2).Concat(list3).FirstOrDefault(e => element.Equals(e));

Upvotes: 3

Tigran
Tigran

Reputation: 62246

you can do something like this:

var list1 = new List<int>{1,2,3,4,5,6,7};
var list2 = new List<int>{0,-3,-4,2};

int elementToPush = 4;//value to find among available lists

var exist = list1.Exists(i=>i==elementToPush) || list2.Exists(j=>j==elementToPush);

If at least one collection required element exists, result is false, otherwise it's true.

One row and no external storage creation.

Hope this helps.

Upvotes: 2

Olivier Jacot-Descombes
Olivier Jacot-Descombes

Reputation: 112324

You could use the LINQ Concat function.

var query = list1.Concat(list2).Where(x => x.Category=="my category");

Upvotes: 3

Chris
Chris

Reputation: 27599

You could probably just create a List of lists and then use linq on that list. It is still creating a new List but it is a list of references rather than duplicating the contents of all the lists.

List<string> a = new List<string>{"apple", "aardvark"};
List<string> b = new List<string>{"banana", "bananananana", "bat"};
List<string> c = new List<string>{"cat", "canary"};
List<string> d = new List<string>{"dog", "decision"};

List<List<string>> super = new List<List<string>> {a,b,c,d};

super.Any(x=>x.Contains("apple"));

the Any call should return after the first list returns true so as requested will not process later lists if it finds it in an earlier list.

Edit: Having written this I prefer the answers using Concat but I leave this here as an alternative if you want something that might be more aesthetically pleasing. ;-)

Upvotes: 1

Related Questions