3

Hi I have allLists that contains lists of string I want to find common items among these string lists i have tried

var intersection = allLists
  .Skip(1)
  .Aggregate(
  new HashSet<string>(allLists.First()),
  (h, e) => { h.IntersectWith(e); return h);`

and also intersection ( hard code lists by index) all of them did not work when I tried

var inter = allLists[0].Intersect(allLists[1]).Intersect(allLists[2])
     .Intersect(allLists[3]).ToList();

foreach ( string s in inter) Debug.WriteLine(s+"\n ");

So how am I going to do this dynamically and get common string items in the lists; is there a way to avoid Linq?

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
kobosh
  • 483
  • 2
  • 7
  • 23

2 Answers2

2

Isn't this the easiest way?

var stringLists = new List<string>[] 
    { 
        new List<string>(){ "a", "b", "c" },
        new List<string>(){ "d", "b", "c" },
        new List<string>(){ "a", "e", "c" }
    };

var commonElements =
    stringLists
        .Aggregate((xs, ys) => xs.Intersect(ys).ToList());

I get a list with just "c" in it.

This also handles the case if elements within each list can be repeated.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • This may be shorter but if you need a different condition for the `Intersect` it's easier to do it with the `GroupBy` then to write a custom `IEqualityComparer`... then it's not the easiest way anymore. – t3chb0t Dec 09 '14 at 07:41
0

I'd do it like this:

class Program
{
    static void Main(string[] args)
    {
        List<string>[] stringLists = new List<string>[] 
        { 
            new List<string>(){ "a", "b", "c" },
            new List<string>(){ "d", "b", "c" },
            new List<string>(){ "a", "e", "c" }
        };

        // Will contian only 'c' because it's the only common item in all three groups.
        var commonItems = 
            stringLists
            .SelectMany(list => list)
            .GroupBy(item => item)
            .Select(group => new { Count = group.Count(), Item = group.Key })
            .Where(item => item.Count == stringLists.Length);

        foreach (var item in commonItems)
        {
            Console.WriteLine(String.Format("Item: {0}, Count: {1}", item.Item, item.Count));
        }
        Console.ReadKey();
    }
}

An item is a common item if it occurs in all groups hence the condition that its count must be equal to the number of groups:

.Where(item => item.Count == stringLists.Length)

EDIT:

I should have used the HashSet like in the question. For lists you can replace the SelectMany line with this one:

.SelectMany(list => list.Distinct())
t3chb0t
  • 16,340
  • 13
  • 78
  • 118
  • how to foreach commonItems? i tried foreach (string ss in commonitems) it says cannot convert anonymous to string – kobosh Dec 09 '14 at 06:50
  • each item in the `commonItems` is an anonymous object with the properties `Count` and `Item` like defined in the `Select`. I edited the answer and added a loop. You can name the properties whatever you like. It's just an example. – t3chb0t Dec 09 '14 at 06:52
  • I should have taken `HashSet` like in the question. I can't explain why I took the `List` but I meat the former one. Or you just need a `Distinct` in the `SelectMany` on the list. – t3chb0t Dec 09 '14 at 07:34