﻿ Most Efficient Way to Compare Two Ienumerables (Or Lists) in Linq - ITCodar

# Most Efficient Way to Compare Two Ienumerables (Or Lists) in Linq

## C#: Compare contents of two IEnumerables

There are quite a few ways. Assume A and B is IEnumerable.

``!A.Except(B).Any() && !B.Except(A).Any()A.Count() == B.Count() && A.Intersect(B).Count() == B.Count()etc``

## What is the shortest way to compare if two IEnumerable<T> have the same items in C#?

Even if the order doesn't matter to you, it doesn't rule out SequenceEqual as a viable option.

``var lst1 = new [] { 2,2,2,2 };var lst2 = new [] { 2,3,4,5 };var lst3 = new [] { 5,4,3,2 };//your current function which will return true//when you compare lst1 and lst2, even though//lst1 is just a subset of lst2 and is not actually equal//as mentioned by Wim Coenen(lst1.Count() == lst2.Count() &&        !lst1.Except(lst2).Any()); //incorrectly returns true//this also only checks to see if one list is a subset of another//also mentioned by Wim Coenenlst1.Intersect(lst2).Any(); //incorrectly returns true//So even if order doesn't matter, you can make it matter just for//the equality check like so:lst1.OrderBy(x => x).SequenceEqual(lst2.OrderBy(x => x)); //correctly returns falselst3.OrderBy(x => x).SequenceEqual(lst2.OrderBy(x => x)); // correctly returns true``

## Most efficient way to compare two generic lists based on id elements contained within nested list (C#)

Your current algorithm seem to be `O(n*m*s*s)` where n = number of existing items, m = number number of potential matches and s = average number of suppliers for each existingItem/PotentialMatch. You could reduce the running time to `O(n*m*s)` by using a hash-set for the matching of suppliers.

A generic version would look like this

``public static IEnumerable<(T1, T2)> SetJoin<T1, T2, TKey>(        IEnumerable<T1> t1s,        IEnumerable<T2> t2s,        Func<T1, IEnumerable<TKey>> t1Key,        Func<T2, IEnumerable<TKey>> t2Key) where TKey : IEquatable<TKey>    {        foreach (var t1 in t1s)        {            var t1Keys = new HashSet<TKey>(t1Key(t1));            foreach (var t2 in t2s)            {                // t2Key(t2) would be called many times,                 // might be worth pre-computing it for each t2.                if (t2Key(t2).Any(t1Keys.Contains))                {                    yield return (t1, t2);                }            }            }    }``

And call it like

``SetJoin<ExistingItems, PotentialMatches, int>(              existingItems,               potentialMatches,              e=> e.Suppliers.Select(s => s.Id),              p => p.Suppliers.Select(s => s.Id))``

Also, while linq result in compact and nice code, it is often faster to write the equivalent logic using regular loops if performance is important.

## Better way of comparing two lists with LINQ?

I would do this:

``var map = allElements.ToDictionary(x => x.Id);    if (!someElements.All(id => map.ContainsKey(id)){    // Return early}var list = someElements.Select(x => map[x])                       .ToList();``

Note that the first line will throw an exception if there are any duplicates in `allElements`.

## How to compare two lists and change one property

Given that your target list is named `targetDocs` and the list you want to check for document existance is `srcDocs` try something like (don't have access to a compiler here so can't test):

``targetDocs.ForEach(d => d.IsActive = srcDocs.Any(sd => sd.id == d.Id))``

I'm assuming that we are talking about `List`s and not other collection types as the ForEach extension method is defined for `List`s.

## LINQ (or something else) to compare a pair of values from two lists (in any order)?

You can do in this way:

Define a custom `IEqualityComparer<FooAttribute>` :

``class FooAttributeComparer : IEqualityComparer<FooAttribute>{    public bool Equals(FooAttribute x, FooAttribute y)    {        return x.Match(y);    }    public int GetHashCode(FooAttribute obj)    {        return 0;        // This makes lookups complexity O(n) but it could be reasonable for small lists         // or if you're not sure about GetHashCode() implementation to do.        // If you want more speed you could return e.g. :        // return obj.Field1.GetHashCode() ^ (17 * obj.Field2.GetHashCode());    }}``

Define an extension method to compare lists in any order and having the same number of equal elements:

``public static bool ListContentIsEqualInAnyOrder<T>(this IEnumerable<T> list1, IEnumerable<T> list2, IEqualityComparer<T> comparer){    var lookup1 = list1.ToLookup(x => x, comparer);    var lookup2 = list2.ToLookup(x => x, comparer);    if (lookup1.Count != lookup2.Count)        return false;    return lookup1.All(el1 => lookup2.Contains(el1.Key) &&             lookup2[el1.Key].Count() == el1.Count());}``

Usage example:

``static void Main(string[] args){    List<FooAttribute> attrs = new List<FooAttribute>    {        new FooAttribute(typeof(int), typeof(double)),        new FooAttribute(typeof(int), typeof(double)),        new FooAttribute(typeof(bool), typeof(float)),        new FooAttribute(typeof(uint), typeof(string)),    };    List<FooAttribute> attrs2 = new List<FooAttribute>    {        new FooAttribute(typeof(uint), typeof(string)),        new FooAttribute(typeof(int), typeof(double)),        new FooAttribute(typeof(int), typeof(double)),        new FooAttribute(typeof(bool), typeof(float)),    };    // this returns true    var listEqual1 = attrs.ListContentIsEqualInAnyOrder(attrs2, new FooAttributeComparer());    // this returns false    attrs2.RemoveAt(1);    var listEqual2 = attrs.ListContentIsEqualInAnyOrder(attrs2, new FooAttributeComparer());}``