转换集合

拥有一组对象。 示意图:

[ { A = 1, B = 1 } { A = 1, B = 2 } { A = 2, B = 3 } { A = 2, B = 4 } { A = 1, B = 5 } { A = 3, B = 6 } ] 

需要:

 [ { A = 1, Bs = [ 1, 2 ] } { A = 2, Bs = [ 3, 4 ] } { A = 1, Bs = [ 5 ] } { A = 3, Bs = [ 6 ] } ] 

LINQ可以吗?

注意:订购很重要。 所以Bs = [5]不能与Bs = [1, 2]合并

鉴于这些简单的类:

 class C { public int A; public int B; } class R { public int A; public List Bs = new List(); } 

你可以这样做:

 var cs = new C[] { new C() { A = 1, B = 1 }, new C() { A = 1, B = 2 }, new C() { A = 2, B = 3 }, new C() { A = 2, B = 4 }, new C() { A = 1, B = 5 }, new C() { A = 3, B = 6 } }; var rs = cs. OrderBy(o => oB). ThenBy(o => oA). Aggregate(new List(), (l, o) => { if (l.Count > 0 && l.Last().A == oA) { l.Last().Bs.Add(oB); } else { l.Add(new R { A = oA, Bs = { oB } }); } return l; }); 

注意 :在上面我假设必须对Bs和As进行排序。 如果不是这样,那么删除排序说明很简单:

 var rs = cs. Aggregate(new List(), (l, o) => { if (l.Count > 0 && l.Last().A == oA) { l.Last().Bs.Add(oB); } else { l.Add(new R { A = oA, Bs = { oB } }); } return l; }); 

所以基本上你想把具有相同A值的东西组合在一起并且是连续的。

您需要将对象列表转换为包含上一个/下一个元素的匿名类型。 我使用了两个Selects来使它更加红色。 然后你需要检查两个元素是否是连续的(相邻的索引)。 现在,您拥有GroupBy ,值和bool所需的一切。

你的对象:

 var list = new System.Collections.Generic.List(){ new Foo(){ A = 1, B = 1 }, new Foo(){ A = 1, B = 2 }, new Foo(){ A = 2, B = 3 }, new Foo(){ A = 2, B = 4 }, new Foo(){ A = 1, B = 5 }, new Foo(){ A = 3, B = 6 } }; 

查询:

 var groups = list .Select((f, i) => new { Obj = f, Next = list.ElementAtOrDefault(i + 1), Prev = list.ElementAtOrDefault(i - 1) }) .Select(x => new { A = x.Obj.A, x.Obj, Consecutive = (x.Next != null && x.Next.A == x.Obj.A) || (x.Prev != null && x.Prev.A == x.Obj.A) }) .GroupBy(x => new { x.Consecutive, xA }); 

输出结果:

 foreach (var abGroup in groups) { int aKey = abGroup.Key.A; var bList = string.Join(",", abGroup.Select(x => x.Obj.B)); Console.WriteLine("A = {0}, Bs = [ {1} ] ", aKey, bList); } 

这是工作演示 : http : //ideone.com/fXgQ3

您可以使用GroupAdjacent扩展方法 。

然后,你只需要

 var grps = objects.GroupAdjacent(p => new { pA }); 

我认为这是实现它的最简单方法。

编辑:

这是我的测试代码。

 class Program { static void Main(string[] args) { var ia = new Dummycls[] { new Dummycls{ A = 1, B = 1 }, new Dummycls{ A = 1, B = 2 }, new Dummycls{ A = 2, B = 3 }, new Dummycls{ A = 2, B = 4 }, new Dummycls{ A = 1, B = 5 }, new Dummycls{ A = 3, B = 6 }, }; var groups = ia.GroupAdjacent(i => iA); foreach (var g in groups) { Console.WriteLine("Group {0}", g.Key); foreach (var i in g) Console.WriteLine(i.ToString()); Console.WriteLine(); } Console.ReadKey(); } } class Dummycls { public int A { get; set; } public int B { get; set; } public override string ToString() { return string.Format("A={0};B={1}" , A , B); } } 

结果是

 Group 1 A=1;B=1 A=1;B=2 Group 2 A=2;B=3 A=2;B=4 Group 1 A=1;B=5 Group 3 A=3;B=6 

这是执行您想要的方法的结构:

 public static IEnumerable> GroupWithKeyBreaks(IEnumerable enumerable, Func keySelector, Func itemSelector) { // Error handling goes here TKey currentKey = default(TKey); List elements = new List(); foreach (T element in enumerable) { TKey thisKey = keySelector(element); if (thisKey == null) { continue; } if (!thisKey.Equals(currentKey) && elements.Count > 0) { yield return new SimpleGrouping(currentKey, elements); elements = new List(); } elements.Add(itemSelector(element)); currentKey = thisKey; } // Add the "last" item if (elements.Count > 0) { yield return new SimpleGrouping(currentKey, elements); } } 

它使用以下帮助程序类:

 private class SimpleGrouping : IGrouping { private T key; private IEnumerable grouping; T IGrouping.Key { get { return key; } } IEnumerator IEnumerable.GetEnumerator() { return grouping.GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return grouping.GetEnumerator(); } public SimpleGrouping(T k, IEnumerable g) { this.key = k; this.grouping = g; } } 

这是一个示例用法:

 foreach (var grouping in data.GroupWithKeyBreaks(x => xA, x => xB)) { Console.WriteLine("Key: " + grouping.Key); foreach (var element in grouping) { Console.Write(element); } } 
 var groupCounter = 0; int? prevA = null; collection .Select(item => { var groupId = item.A == prevA ? groupCounter : ++groupCounter; prevA = item.A; return new { groupId, item.A, item.B }; }) .GroupBy(item => item.groupId) .Select(grp => new { A = grp.First().A, Bs = grp.Select(g => gB) }); 

如果你的collections是在o ,那么:

  var trans = o.Aggregate ( new { List = new List>>(), LastSeed = (int?)0 }, (acc, item) => { if (acc.LastSeed == null || item.A != acc.LastSeed) acc.List.Add(Tuple.Create(item.A, new List())); acc.List[acc.List.Count - 1].Item2.Add(item.B); return new { List = acc.List, LastSeed = (int?)item.A}; }, acc => acc.List.Select( z=>new {A = z.Item1, B = z.Item2 as IEnumerable }) ); 

这会生成所需表单的IEnumerable>

 var result = list.ToKeyValuePairs(x => xA) .Select(x => new { A = x.Key, Bs = x.Value.Select(y => yB) }); foreach (var item in result) { Console.WriteLine("A = {0} Bs=[{1}]",item.A, String.Join(",",item.Bs)); } 

 public static class MyExtensions { public static IEnumerable>> ToKeyValuePairs( this IEnumerable list, Func keySelector) { List retList = new List(); S prev = keySelector(list.FirstOrDefault()); foreach (T item in list) { if (keySelector(item).Equals(prev)) retList.Add(item); else { yield return new KeyValuePair>(prev, retList); prev = keySelector(item); retList = new List(); retList.Add(item); } } if(retList.Count>0) yield return new KeyValuePair>(prev, retList); } } 

OUTPUT:

 A = 1 Bs=[1,2] A = 2 Bs=[3,4] A = 1 Bs=[5] A = 3 Bs=[6]