Ahmad
Ahmad

Reputation: 9658

How to group by and count similar lists in a List<List<String>>

I have a list of a list of strings:

 List<List<String>> pChain;

It might have repeated lists of strings (two list of strings are equal if they have the same strings in the same order). I want to have the count of each distinct list in the main list. I tried:

var results = (from t in pChain

               group t by new { t }
                   into g
                   select new
                   {
                       g.Key,
                       Count = g.Count(),
                   }).OrderByDescending(x => x.Count).ToList();

foreach (var v in results)
{
    ListViewItem lv = listView2.Items.Add(v.Key.ToString());

    lv.SubItems.Add(v.Count + "");
}

But it doesn't group similar list of strings into one list and doesn't count them.

Upvotes: 0

Views: 101

Answers (3)

Ahmad
Ahmad

Reputation: 9658

I tried Aggregate function to join the strings of the inner list to a string resulted from concatenating them. Then applied the GroupBy to this list.

 Dictionary<string, int> itemCounts = 
 pChain.Select(list => list.Aggregate((i, j) => j + '/' + i))
.GroupBy(item => item).OrderByDescending(x => x.Key)
.ToDictionary(g => g.Key.ToString(), g => g.Count());

 foreach (var v in itemCounts)
 {
     ListViewItem lv = listView2.Items.Add(v.Key.ToString());

     lv.SubItems.Add(v.Value + "");
 }

Upvotes: 0

Innat3
Innat3

Reputation: 3576

You can check if a list of lists contains an specific list by iterating through its elements and checking if they are SequenceEqual(). You should be able to remove the duplicate lists with this:

for(int i = 0; i < pChain.Count(); i++)
{
    // If the amount(Count) of SequenceEqual lists in pChain for the current iteration 
    // of pChain (pChain[i]) is > 1
    if (pChain.Count(l => l.SequenceEqual(pChain[i])) > 1)
        pChain.RemoveAt(i);
}

Thus the amount of distinct lists would be:

int count = pChain.Count();

You can put the code above into a single linQ line this way:

pChain.Select((x, y) => new { list = x, Index = y }).ToList()
      .ForEach(l1 => { 
          if (pChain.Count(l2 => l2.SequenceEqual(l1.list)) > 1)
              pChain.RemoveAt(l1.Index);
       });

Upvotes: 1

Tim Schmelter
Tim Schmelter

Reputation: 460158

You can use SelectMany + Distinct:

var allDistinctItems = pChain.SelectMany(list => list).Distinct();

If you want the count use int countOfDistinctItems = allDistinctItems.Count();.

If you want a dictionary you could use:

Dictionary<string, int> itemCounts = pChain.SelectMany(list => list)
    .GroupBy(item => item)
    .ToDictionary(g => g.Key, g => g.Count());

Upvotes: 6

Related Questions