Compare Two List<Objects> - c#

What is the best route to compare 2 List<MyClasses>?
List 2 could contain more values than List 1 which is ok. Just need to make sure List 2 contains everything in List 1. They also won't be in the same order.

You can use Except to find the set difference of two collections.
var hasAllItems = !list2.Except(list1).Any();

The simplest approach is to use Except (in your case, you don't care about the order of your elements in the lists):
var elementsInList2NotInList1 = list2.Except(list1);
Remember that this method uses a default equality comparer to compare the values. If you do care about the ordering of the elements, you'll need to do extra work, in order to check how each element of a list is equal to an element of the other list. The extra work would be the following:
Create your own comparer, implementing the interface IEqualityComparer;
Create your own Equals() and GetHashCode() methods for your custom data type.

One way to do it:
List1.All(o => List2.Contains(o));
This says "return true if and only if every item in list 1 is contained in list 2"

This will let you know if list2 does not contain an item that is in list1:
list1.Any(x => !list2.Contains(x));
You could put it in a variable so you don't have to think about the double negatives:
var list2ContainsList1 = !list1.Any(x => !list2.Contains(x));

Related

How do I use Any() instead of RemoveAll() to exclude list items?

ListWithAllItems contains two type of items: ones I want select, and ones that I don't.
listForExcluding contains item that I should to exclude:
List<string> listForExcluding = ...;
So I do it in two strings:
List<string> x = ListWithAllItems.ToList();
x.RemoveAll(p => listForExcluding.Any(itemForExclude => itemForExclude == p));
How do I use Any() instead of RemoveAll() to get this query with one line?
Any doesn't make sense here, just use Except:
var filtered = ListWithAllItems.Except(listForExcluding);
ToList if you actually need a list at the end, otherwise don't realize IEnumerables for no reason (causes an extra enumeration).
If you really want the RemoveAll version for some reason, use Contains (this is also how to do it using Where):
x.RemoveAll(p => listForExcluding.Contains(p));
There's a number of other valid lines... but seriously just go with Except

What is the best way to search for a string in a list of list of strings c#

What is the best way to search for a string in a list of lists of strings?
Example I have many lists of strings e.g. List1 List 2 etc. and all of the lists are collected in a List of Lists (e.g. ListofLists<,...>.
Now I want to search for the string "foo" in the list of lists. Is there a way to optimize this in c#?
Thanks in advance
Using Linq:
To check if any of the lists contains the string 'foo':
collection.Any(x => x.Contains("foo"));
To get the particular list which contains the string 'foo':
collection.FirstOrDefault(x => x.Contains("foo"));
Does this work?
var listOfLists = new List<List<string>>();
// insert code to populate listOfLists
var containsFoo = listOfLists.SelectMany(x => x).Any(x => x == "foo");
I'll just summarize/optimize other answers:
The best way to do this is using LINQ. Therefore you could use two ways:
You could flaten the list and look wether it contains an element
You could check all lists wether one list contains the element
Flaten the list
This is done with SelectMany:
listOfLists.SelectMany(x => x).Contains("foo");
SelectMany combines all elements of the sublists and sublists of the sublists (and so on) into one list, so you can check all items, wether one contains the string (https://msdn.microsoft.com/de-de/library/bb534336(v=vs.110).aspx).
Check all lists
This is done with Any:
listOfLists.Any(x => x.Contains("foo"));
Any checks wether any item fulfills the condition (https://msdn.microsoft.com/de-de/library/bb337697(v=vs.110).aspx).
Actually it seems to be more efficient to check all lists (With a randomly generated list with a total of 10,000 entries the first possibility needs averragely 34ms and the second one 31).
In both possibilities I use Contains, which simply checks, wether the list contains the element (https://msdn.microsoft.com/de-de/library/bb352880(v=vs.110).aspx).
Of course you could still use a loop as well:
var contains = false;
foreach (var l in listOfLists)
foreach (var i in l)
if (i == "foo")
{
contains = true;
goto end;
}
end:
But this is less readable, less effective, more complicated and less elegant.
However, if you don't just want to check, wether it exists, but do a bit more with it, the last possibility is possibly the easiest one. If you want an optimized version for another case, feel free to specify your requirements.

How to group a List<T> that has a property of List<string> by that nested List?

I have a custom data type that contains a List<string>.
I wish to group a List of CustomDataType by that nested List<string>.
I have tried the following
compoundSchedules.GroupBy(a => a.Timepoints);
Where Timepoints is a list of dates represented as strings. Where any CustomDataTypes have identical timepoints, I wish them to be grouped together.
Using the code above, it does not group them and instead just repeats the List of CustomDataType with its timepoint list as the IGrouping Key.
Thanks.
You should create an IEqualityComparer<List<string>> that checks that the lists have the same length and contents, and use this overload of Enumerable.GroupBy:
compoundSchedules.GroupBy(a => a.Timepoints, myComparer);
Either that, or create your own class to be a list of Timepoints, and have it implement GetHashCode and Equals (and/or implement IEquatable<T>), which are used by the default comparer.
Two things come to mind. First is to create a Timepoints class and implement IComparable. Then you can compare each element of each list to see if they are equivalent. Alternatively, you could create a new property on your compound schedule that holds the hash code for the list.
Since Timepoints is a List<string> - I would construct one aggregated string and group by that. You can accomplish this by using the Aggregate method
compoundSchedules.GroupBy(a => a.Timepoints.Aggregate( (x,y) => x + y));
You could group by the joined list of strings:
var grouped = compoundSchedules.GroupBy(cs => string.Join("", cs.Timepoints));
This would also take care of the same order (if this is desired).

get fixed number of items from array list c#

I would like to create a list variable of items from another list. So lets say I have a list of 100 items I would like to pull items 25 - 35 and put them inside of another list. is there a way of doing this without calling a big for statement and pulling out the element one by one and putting that into a list.
you can use .Skip and .Take from System.Linq ....
Like this:
var result = myList.Skip(24).Take(10);
and if you need use ToList on the result to get another list
For a List<T>, you can use the GetRange Method.
Creates a shallow copy of a range of elements in the source List(Of
T).
Do note that the second argument represents the count of elements in the range, not the end-index of the range.
Since you mention ArrayList, I should point out that while it too has a GetRange, method, the type is considered essentially legacy since .NET 2.0.
Use both Take and Skip
var newList = oldList.Skip(25).Take(10);

Removing a list of objects from another list

I've been looking for something like that for days. I'm trying to remove all the elements from a bigger list A according to a list B.
Suppose that I got a general list with 100 elements with differents IDS and I get another list with specific elements with just 10 records. I need remove all the elements from the first list that doesn't exists inside the second list.
I'll try to show the code that I actually don't know how it didnt works.
List<Obj> listA = new List<Obj>();
List<Obj> listB = new List<Obj>();
//here I load my first list with many elements
//here I load my second list with some specific elements
listA.RemoveAll(x => !listB.Contains(x));
I don't know why but it's not working. If I try this example with a List<int> type, it works nicely but I'd like to do that with my object. This object got an ID but I don't know how to use this ID inside the LINQ sentence.
You need to compare the IDs:
listA.RemoveAll(x => !listB.Any(y => y.ID == x.ID));
List(T).RemoveAll
I believe you can use the Except Extension to do this.
var result = listA.Except(listB)
Reference: http://www.dotnetperls.com/except
If you want to remove a list of objects (listB) from another list (listA) use:
listA = listA.Except(listB).ToList()
Remember to use ToList() to convert IEnumerable<Obj> to List<Obj>.
who ever is viewing this now.I think var result = listA.Intersect(listB) will give the result for common values in the both the list.
According to the documentation on MSDN ( http://msdn.microsoft.com/en-us/library/bhkz42b3.aspx ), contains uses the default Equality comparer to determine equality, so you could use IEquatable's Equals method on your Obj class to make it work. HiperiX mentions the ref comparison above.
How to add the IEquateable interface: http://msdn.microsoft.com/en-us/library/ms131190.aspx

Categories

Resources