Intelligent Grouping with LINQ

I have a list of strings, and I want to convert it to some sort of a grouped list, in which the values ​​will be grouped by their location in the list (not an ordinary grouping, but in a sense that the same elements are in the group list, only if they are together). Consider the following example:

LinkedList<string> myList = new LinkedList<string>(); myList.AddLast("aaa"); myList.AddLast("aaa"); myList.AddLast("bbb"); myList.AddLast("bbb"); myList.AddLast("aaa"); myList.AddLast("aaa"); myList.AddLast("aaa"); LinkedList<MyTuple> groupedList = new LinkedList<MyTuple>(); groupedList.AddLast(new MyTuple("aaa", 2)); groupedList.AddLast(new MyTuple("bbb", 2)); groupedList.AddLast(new MyTuple("aaa", 3)); 

Can this conversion be done using LINQ, or can I write a regular algorithm using loops?

+6
dictionary list c # linq
source share
2 answers

The extension method from this answer does pretty much what you ask (Microsoft also provides an implementation for grouping related elements in a sequence ):

 public static IEnumerable<IGrouping<int, T>> GroupConsecutive<T>(this IEnumerable<T> set, Func<T, T, bool> predicate) { var i = 0; var k = 0; var ranges = from e in set let idx = ++i let next = set.ElementAtOrDefault(idx) let key = (predicate(e, next)) ? k : k++ group e by key into g select g; return ranges; } 

You can use it as follows:

 void Main() { LinkedList<string> myList = new LinkedList<string>(); myList.AddLast("aaa"); myList.AddLast("aaa"); myList.AddLast("bbb"); myList.AddLast("bbb"); myList.AddLast("aaa"); myList.AddLast("aaa"); myList.AddLast("aaa"); IGrouping<int,string> ggg; var groups=myList.GroupConsecutive((a,b)=>a==b); ILookup<string,int> lookup=groups.ToLookup(g=>g.First(),g=>g.Count()); foreach(var x in lookup["aaa"]) { Console.WriteLine(x); //outputs 2 then 3 } foreach(var x in lookup["bbb"]) { Console.WriteLine(x); //outputs 2 } } 

Note that the final container is an ILookup , which behaves like a dictionary, but allows you to store multiple values ​​by one key.

+4
source share

This is not possible in the dictionary. The dictionary is associative (i.e., each key must point to only one and one) and is inherently disordered. You will need to use something else for this data structure. It would be terribly difficult!

Edit

A List<Tuple<string, int>> should do the trick:

 List<KeyValuePair<string, int>> structure = new List<KeyValuePair<string, int>>(); structure.Add(new KeyValuePair<string, int>(myList[0], 1); for(int i = 0; i < myList.Count; i++ ) { if( myList[i] == structure[structure.Count-1].Key ) { structure[structure.Count-1].Value += 1; } else { structure.Add(new KeyValuePair<string, int>(myList[i], 1); } } 

After that, you should (unverified!) Have what you are looking for.

Change (another thought)

Although this is possible with linq (using TakeWhile and counts ...), I still think it makes sense to use a loop here, it's simple. Someone brighter than I could try and work with Linq.

+1
source share

All Articles