使用LINQ进行“智能”分组

我有一个字符串列表,我想将其转换为某种分组列表,其中值将按列表中的位置进行分组(不是正常分组,但在某种程度上,相同的项目只在一个组中如果他们在一起)。 请考虑以下示例:

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

这个转换可以用LINQ完成,还是应该用循环编写算法?

这个答案的扩展方法几乎可以满足你的要求(微软还提供了一个实现来对序列中的连续项进行分组 ):

 public static IEnumerable> GroupConsecutive(this IEnumerable set, Func 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; } 

您可以按如下方式使用它:

 void Main() { LinkedList myList = new LinkedList(); myList.AddLast("aaa"); myList.AddLast("aaa"); myList.AddLast("bbb"); myList.AddLast("bbb"); myList.AddLast("aaa"); myList.AddLast("aaa"); myList.AddLast("aaa"); IGrouping ggg; var groups=myList.GroupConsecutive((a,b)=>a==b); ILookup 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 } } 

请注意,最终容器是一个ILookup ,其行为有点像Dictionary,但允许一个人针对单个键存储多个值。

“词典”无法实现这一点。 字典是关联的(即:每个键必须指向一个和一个)并且本质上是无序的。 您需要为该数据结构使用其他东西。 虽然这不会太难!

编辑

List>应该可以做到这一点:

 List> structure = new List>(); structure.Add(new KeyValuePair(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(myList[i], 1); } } 

之后你应该(未经测试!)拥有你想要的东西。

编辑(再想一想)

虽然有可能使用linq(使用TakeWhile并计算…),但我仍然认为在这里使用循环更有意义,这很简单。 比我更有能力和Linq一起工作的人。