tags:

views:

75

answers:

3

Hello... I have two lists:

List<string> _list1;
List<string> _list2;

I need add all _list2 different items on _list1...

How can I do that using LINQ?

Thanks

+9  A: 

You would use the IEnumerable<T>.Union method:

var _list1 = new List<string>(new[] { "one", "two", "three", "four" });
var _list2 = new List<string>(new[] { "three", "four", "five" });

_list1 = _list1.Union(_list2);

// _distinctItems now contains one, two, three, four, five

EDIT

You could also use the method the other post uses:

_list1.AddRange(_list2.Where(i => !_list1.Contains(i));

Both of these methods are going to have added overhead.

The first method uses a new List to store the Union results (and then assigns those back to _list1).

The second method is going to create an in-memory representation of Where and then add those to the original List.

Pick your poison. Union makes the code a bit clearer in my opinion (and thus worth the added overhead, at least until you can prove that it is becoming an issue).

Justin Niessner
This creates a new list; it doesn't add anything to _list1.
Gabe
@Gabe - Problem solved.
Justin Niessner
This creates a new List with the Union of the two. Not adding to the original list
Carlos Muñoz
@Carlos - Any specific reason to not use this?
Justin Niessner
Well in this particular example it's fine. But if the Collection has some sort of state like some ORM lists of objects they could fail when updating to the DB since the collection that has all the DB-related information is the one that was lost when assining the new one.
Carlos Muñoz
@Carlos - Either of the methods describe here are going to rely on Equals. Both Union and Contains allow you to supply your own IComparer to use instead of relying on Equals. You're right about the ORM issue though. If you're working with ORM managed Lists (that handle Inserts, etc.), then AddRange would be the option that more correctly defines your intent.
Justin Niessner
@Justin: Yes my mistake, I edited my comment. I have suffered already when merging two lists that is why I remember this case
Carlos Muñoz
+1 I like simplicity with Union but I believe AddRange(list2.Except(..)) is faster than your second approach (See comment on Carlos' answer). Union is properly a little bit slower than AddRange(list2.Except(..)) because you create a new List but asymptotically it should be the same I guess.
lasseespeholt
+5  A: 
_list1.AddRange( _list2.Where(x => !_list1.Contains(x) ) );
Carlos Muñoz
Won't this run in O(n^2)? Ideally it should not be slower than sorting which is O(n*log(n)) for comparison-sorts.
lasseespeholt
@lasseespeholt You can't be sure if the Lists are sorted.
Carlos Muñoz
@Carlos That is not what I'm saying. I'm saying that I think the performance of your expression is O(n*m) where n is list1.Length and m is list2.Length. And it should not be slower than sorting which can be done in O(n*log n) because if you are concatenating the lists and sorts then you can remove duplicates in O(n) time so it will be O(n*log n).
lasseespeholt
http://stackoverflow.com/questions/2799427 This states that Union is O(n) which is A LOT faster than that.
lasseespeholt
@lasseespeholt Why does it have to be not slower than sorting? I didn't see it as a requirement. Also since you have two unsorted lists there is no other way (i can think of) of finding out which of the elements in the second list are in the first other than searching secuentially. And you have to do this for all items of second list so it has to be O(n^2).
Carlos Muñoz
@Carlos - You could add the items in the first list into a `HashSet<T>` and then test for membership of each item in the second - this approach is linear in the length of the longer list. This is why using Union and Except are more efficient.
Lee
@Carlos I meant there is a solution which is at least as fast as sorting. Union, Except and Distinct is O(n). It ain't a requirement but Paul should at least know this solution is slow. And furthermore is it longer than the faster solution. This is not some personal hetz and I haven't down-voted because this is indeed a correct answer. But again, this is not a optimal nor pretty solution and therefore have I up-voted, in my head, better solutions. Regards...
lasseespeholt
I also have upvoted the other solution which apperead I think after mine so I have no problem with that
Carlos Muñoz
+6  A: 
list1.AddRange(list1.Except(list2));
Lee
+1 I believe this would be a lot faster than Carlos answer. (See comment on his answer)
lasseespeholt