var list1 = new[] { 1, 2, 3, 4, 5 };
var list2 = new int[] { };
var x = list2.Except(list1).ToList();
This doesnt return all elements from list1, var x is actually an empty list. according to msdn it should return all the elements in list1. Why is it not, and what am I missing.
A sequence that contains the set difference of the elements of two sequences.
It works just fine: returns all items from list2 which do not exist in list1. And because list2 is already empty result list is empty as well.
Look at first parameter description on the msdn:
An IEnumerable<T> whose elements that are not also in second will be returned.
The wording might be confusing on MSDN, but refer to set theory to understand it.
A sequence that contains the set difference of the elements of two sequences.
A set difference is also called a complement and is "is the set of elements in B but not in A".
With that in mind, an empty array .Except anything is still an empty array.
You probably want
var list1 = new[] { 1, 2, 3, 4, 5 };
var list2 = new int[] { };
var x = list2.Union(list1).ToList();
Since you mentioned that you are expecting
should return all the elements in list1
Related
I have two lists of string. I want to compare each elements in one list with another and if at least one of them match then do some processing else dont do anything.
I dont know how to do. I do have the following lists and the code I used was SequenceEqual but my lead said its wrong as it just compares if its equal or not and does nothing. I couldn't disagree and I want to achieve my intended functionality I mentioned above. Please help. As you seem, order doesn't matter, here 123 is in both list but in different order, so it matches and hence do some processing as per my requirement.
List<string> list1 = new List<string> () { "123", "234" };
List<string> list2 = new List<string> () { "333", "234" , "123"};
You can use the Any method for this :
var matchfound = list1.Any(x=> list2.Contains(x));
Now you can do conditional block on the matchFound if it returns true you can process what ever is required.
if you want to do case insentitive comparison then you will need to use String.Equals and can specify if case does not matter for comaparing those.
You can use Intersect to find common elements:
var intersecting = list1.Intersect(list2);
If you just want to know if there are common elements append .Any():
bool atLeastOneCommonElement = intersecting.Any();
If you want to process them:
foreach(var commonElement in intersecting)
{
// do something ...
}
You could check with Intersect and Any
var matchFound = list1.Intersect(list2).Any();
For example,
List<string> list1 = new List<string>{ "123", "234" };
List<string> list2 = new List<string>{ "333", "234" , "123"};
var result = list1.Intersect(list2).Any();
Output True
List<string> list3 = new List<string>{"5656","8989"};
result = list1.Intersect(list3).Any();
Output False
You need to take all those item that are matches from both list and then do code if match found like
foreach (var item in list1.Where(x => list2.Contains(x)))
{
//do some processing here
Console.WriteLine($"Match found: {item}");
}
In above code foreach iterate when item present in both list.
Output:
Use LINQ to find the matches; and then check the resulting array size as follows:
var intersect = list1.Where(el1=>list2.Any(el2=>el2==el1));
var isMatch = intersect.Count > 0;
I have two List<string>:
List 1:
snap
crackle
List 2:
snap
crackle
pop
bang
List 2 will always start with the same elements as List 1, but will always have some extra elements "hanging off the end." I want to return a list of just these "overhang elements."
So in the above example, I want a list of:
pop
bang
Is there a LINQ operator that does this?
You can use Except extension method:
var list1 = new List<string> { "snap", "crackle" };
var list2 = new List<string> { "snap", "crackle", "pop", "bang" };
var result = list2.Except(list1).ToList();
Ivan Stoev pointed that the solution above will produce the set difference. If you want the list difference and the second list always contains elements from the first list at the beginning you can use this solution:
var result = list2.Skip(list1.Count).ToList();
Run this example on .NET Fiddle.
You can use the Except() linq method to do this:
var onlyIn2 = list2.Except(list1);
I have two Lists, and I've values in these as,
List1 List2
----- -----
1 1
2 2
3
I've to compare the second list with the first list, and I've to return the values which is not in the List1(here "3"), how can we compare two lists like this?
can anyone help me?
Use LINQ and the Except extension method.
var list1 = new List<int> { 1, 2 };
var list2 = new List<int> { 1, 2, 3 };
var remaining = list2.Except(list1);
Try this:
var result = list2.Except(list1);
Note that it's considered bad style to use initial capitals on your variable names (unless they're actually properties) :-)
Here you go: http://msdn.microsoft.com/en-us/library/bb300779.aspx
Rarest examples on msdn which i found useful.
This is probable a common question, and I have searched other question without finding a solution that works (note, my skill in C# and linq is limited - so a simple solution would be appreciated!).
Here is the issue:
I have 2 lists with objects. I want to compare them and return all the NEW objects in list2.
Example:
ObjectList List1; // contains 3 objects that is stored in the database
ObjectList List2; // contains the same 3 objects as in List1 and a new object that was added from a webpage (the parent object was updated on the webpage)
ObjectList List3; // should do a compare of List1 and List2, and return the NEW objects in List2 (so the result should only be Object number 4)
Note:
The order does not matter. I only want the new object(s)
Normally objects are only added to List2. IF any object is removed (compare to List1), then this should be ignored. (so object that only exists in List1 is of no interest)
Thanks for any suggestions or links to previously questions i missed in my search
Edit
Here is a small example of first try with Except (this returned an error)
I have shortened it a bit. The method is from our software, so they are probable not know to you. Sorry about that.
// caDialogObjects = List1 (caDialogQLMLinks is the link to the objects)
RepositoryObjectList caDialogObjects = args.Object.GetConfiguration().GetObjectSet(caDialogQLMLinks);
// caObjectObjects = List2 (caObjectQLMLinks is the link to the objects)
RepositoryObjectList caObjectObjects = args.Object.GetConfiguration().GetObjectSet(caObjectQLMLinks);
// List 3
RepositoryObjectList caTotal;
caTotal = caObjectObjects.Except(caDialogObjects);
Solution that worked
The Exception did not work since the list is just a reference (not a value). It is possible to use the second parameter, but i got a linq code that worked:
RepositoryObjectList caNewCA =
new RepositoryObjectList(caDialogObjects.Where(item1 =>
!caObjectObjects.Any(item2 => item1.Id == item2.Id)));
Use this:
var list3 = list2.Except(list1);
This uses the Except extension method which returns all elements in list2 that are not in list1.
It is important to note, that Except returns an IEnumerable<T> where T is the type of the object inside list1 and list2.
If you need your list3 to be of a specific type, you need to convert that return value. In the simplest case, your target type has a constructor that can handle and IEnumerable<T>:
RepositoryObjectList list3 = new RepositoryObjectList(list2.Except(list1));
List<MyObject> objectList1 = new List<MyObject>();
List<MyObject> objectList2 = new List<MyObject>();
List<MyObject> objectList3 = objectList2.Where(o => !objectList1.Contains(o)).ToList();
This should do it, as long as MyObject is IComparable
http://msdn.microsoft.com/en-us/library/system.icomparable.aspx
Here's an example of how you could do it using LINQ:
List<int> l1 = new List<int>();
List<int> l2 = new List<int>();
l1.AddRange(new int[] {1, 2, 3, 5});
l2.AddRange(new int[] {1, 2, 3, 4});
// get only the objects that are in l2, but not l1
var l3 = l2.Except(l1);
The third list will only contain one element, 4.
secondList.Except(firstList)
which uses
public static IEnumerable<TSource> Except<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second
)
http://msdn.microsoft.com/en-us/library/bb300779.aspx
or
secondList.Except(firstList,new CustomComparer())
which uses
public static IEnumerable<TSource> Except<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second,
IEqualityComparer<TSource> comparer
)
http://msdn.microsoft.com/en-us/library/bb336390.aspx
I'd like to use Remove() method on list of lists, but it's not working for me.
Simple example should say everything:
List<List<int>> list = new List<List<int>>();
list.Add(new List<int> { 0, 1, 2 });
list.Add(new List<int> { 1, 2 });
list.Add(new List<int> { 4 });
list.Add(new List<int> { 0, 1, });
list.Remove(new List<int> { 1, 2 });
If I use RemoveAt(1) it works fine but Remove() not.
It is obviously the same reason that this code returns false:
List<int> l1 = new List<int>();
List<int> l2 = new List<int>();
l1.Add(1);
l2.Add(1);
bool b1 = l1 == l2; // returns False
bool b2 = l1.Equals(l2); // returns False too
So it seems to me that I cannot simply compare two lists or even arrays. I can use loops instead of Remove(), but there must be easier way.
Thanks in advance.
The problem is that List<T> doesn't override Equals and GetHashCode, which is what List<T> will use when trying to find an item. (In fact, it will use the default equality comparer, which means it'll use the IEquatable<T> implementation if the object implements it, and fall back to object.Equals/GetHashCode if necessary). Equals will return false as you're trying to remove a different object, and the default implementation is to just compare references.
Basically you'd have write a method to compare two lists for equality, and use that to find the index of the entry you want to remove. Then you'd remove by index (using RemoveAt). EDIT: As noted, Enumerable.SequenceEqual can be used to compare lists. This isn't as efficient as it might be, due to not initially checking whether the counts are equal when they can be easily computed. Also, if you only need to compare List<int> values, you can avoid the virtual method call to an equality comparer.
Another alternative is to avoid using a List<List<int>> in the first place - use a List<SomeCustomType> where SomeCustomType includes a List<int>. You can then implement IEquatable<T> in that type. Note that this may well also allow you to encapsulate appropriate logic in the custom type too. I often find that by the type you've got "nested" collection types, a custom type encapsulates the meaning of the inner collection more effectively.
First approach:
List<int> listToRemove = new List<int> { 1, 2 };
list.RemoveAll(innerList => innerList.Except(listToRemove).Count() == 0);
This also removes the List { 2, 1 }
Second approach (preferred):
List<int> listToRemove = new List<int> { 1, 2 };
list.RemoveAll(innerList => innerList.SequenceEqual(listToRemove));
This removes all lists that contain the same sequence as the provided list.
List equality is reference equality. It won't remove the list unless it has the same reference as a list in the outer list. You could create a new type that implements equality as set equality rather than reference equality (or you do care about order as well?). Then you could make lists of this type instead.
This simply won't work because you're tying to remove a brand new list (the new keyword kind of dictates such), not one of the ones you just put in there. For example, the following code create two different lists, inasmuch as they are not the same list, however much they look the same:
var list0 = new List<int> { 1, 2 };
var list1 = new List<int> { 1, 2 };
However, the following creates one single list, but two references to the same list:
var list0 = new List<int> { 1, 2 };
var list1 = list0;
Therefore, you ought to keep a reference to the lists you put in there should you want to act upon them with Remove in the future, such that:
var list0 = new List<int> { 1, 2 };
listOfLists.Remove(list0);
They are different objects. Try this:
List<int> MyList = new List<int> { 1, 2 };
List<List<int>> list = new List<List<int>>();
list.Add(new List<int> { 0, 1, 2 });
list.Add(MyList);
list.Add(new List<int> { 4 });
list.Add(new List<int> { 0, 1, });
list.Remove(MyList);
You need to specify the reference to the list you want to remove:
list.Remove(list[1]);
which, really, is the same as
list.RemoveAt(1);