using System;
using System.Linq;
using System.Collections.Generic;
class Foo
{
public int A { get; set; }
public int B { get; set; }
}
public class GroupOfAdjacent<TSource, TKey> : IEnumerable<TSource>, IGrouping<TKey, TSource>
{
public TKey Key { get; set; }
private List<TSource> GroupList { get; set; }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return ((System.Collections.Generic.IEnumerable<TSource>)this).GetEnumerator();
}
System.Collections.Generic.IEnumerator<TSource> System.Collections.Generic.IEnumerable<TSource>.GetEnumerator()
{
foreach (var s in GroupList)
yield return s;
}
public GroupOfAdjacent(List<TSource> source, TKey key)
{
GroupList = source;
Key = key;
}
}
public static class LocalExtensions
{
public static IEnumerable<IGrouping<TKey, TSource>> GroupAdjacent<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector)
{
TKey last = default(TKey);
bool haveLast = false;
List<TSource> list = new List<TSource>();
foreach (TSource s in source)
{
TKey k = keySelector(s);
if (haveLast)
{
if (!k.Equals(last))
{
yield return new GroupOfAdjacent<TSource, TKey>(list, last);
list = new List<TSource>();
list.Add(s);
last = k;
}
else
{
list.Add(s);
last = k;
}
}
else
{
list.Add(s);
last = k;
haveLast = true;
}
}
if (haveLast)
yield return new GroupOfAdjacent<TSource, TKey>(list, last);
}
}
public class Test
{
public static void Main()
{
var list = new System.Collections.Generic.List<Foo>(){
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.GroupAdjacent(x => x.A);
foreach (var abGroup in groups)
{
int aKey = abGroup.Key;
var bList = string.Join(",", abGroup.Select(x => x.B.ToString()).ToArray());
Console.WriteLine("A = {0}, Bs = [ {1} ] ", aKey, bList);
}
}
}
dXNpbmcgU3lzdGVtOwp1c2luZyBTeXN0ZW0uTGlucTsKdXNpbmcgU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWM7CiAKICAgIGNsYXNzIEZvbwogICAgewogICAgICAgcHVibGljIGludCBBIHsgZ2V0OyBzZXQ7IH0KICAgICAgIHB1YmxpYyBpbnQgQiB7IGdldDsgc2V0OyB9CiAgICB9CgogICAgcHVibGljIGNsYXNzIEdyb3VwT2ZBZGphY2VudDxUU291cmNlLCBUS2V5PiA6IElFbnVtZXJhYmxlPFRTb3VyY2U+LCBJR3JvdXBpbmc8VEtleSwgVFNvdXJjZT4KICAgIHsKICAgICAgICBwdWJsaWMgVEtleSBLZXkgeyBnZXQ7IHNldDsgfQogICAgICAgIHByaXZhdGUgTGlzdDxUU291cmNlPiBHcm91cExpc3QgeyBnZXQ7IHNldDsgfQogICAgICAgIFN5c3RlbS5Db2xsZWN0aW9ucy5JRW51bWVyYXRvciBTeXN0ZW0uQ29sbGVjdGlvbnMuSUVudW1lcmFibGUuR2V0RW51bWVyYXRvcigpCiAgICAgICAgewogICAgICAgICAgICByZXR1cm4gKChTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5JRW51bWVyYWJsZTxUU291cmNlPil0aGlzKS5HZXRFbnVtZXJhdG9yKCk7CiAgICAgICAgfQogICAgICAgIFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLklFbnVtZXJhdG9yPFRTb3VyY2U+IFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLklFbnVtZXJhYmxlPFRTb3VyY2U+LkdldEVudW1lcmF0b3IoKQogICAgICAgIHsKICAgICAgICAgICAgZm9yZWFjaCAodmFyIHMgaW4gR3JvdXBMaXN0KQogICAgICAgICAgICAgICAgeWllbGQgcmV0dXJuIHM7CiAgICAgICAgfQogICAgICAgIHB1YmxpYyBHcm91cE9mQWRqYWNlbnQoTGlzdDxUU291cmNlPiBzb3VyY2UsIFRLZXkga2V5KQogICAgICAgIHsKICAgICAgICAgICAgR3JvdXBMaXN0ID0gc291cmNlOwogICAgICAgICAgICBLZXkgPSBrZXk7CiAgICAgICAgfQogICAgfQogICAgcHVibGljIHN0YXRpYyBjbGFzcyBMb2NhbEV4dGVuc2lvbnMKICAgIHsKICAgICAgICBwdWJsaWMgc3RhdGljIElFbnVtZXJhYmxlPElHcm91cGluZzxUS2V5LCBUU291cmNlPj4gR3JvdXBBZGphY2VudDxUU291cmNlLCBUS2V5PigKICAgICAgICAgICAgdGhpcyBJRW51bWVyYWJsZTxUU291cmNlPiBzb3VyY2UsCiAgICAgICAgICAgIEZ1bmM8VFNvdXJjZSwgVEtleT4ga2V5U2VsZWN0b3IpCiAgICAgICAgewogICAgICAgICAgICBUS2V5IGxhc3QgPSBkZWZhdWx0KFRLZXkpOwogICAgICAgICAgICBib29sIGhhdmVMYXN0ID0gZmFsc2U7CiAgICAgICAgICAgIExpc3Q8VFNvdXJjZT4gbGlzdCA9IG5ldyBMaXN0PFRTb3VyY2U+KCk7CiAgICAgICAgICAgIGZvcmVhY2ggKFRTb3VyY2UgcyBpbiBzb3VyY2UpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIFRLZXkgayA9IGtleVNlbGVjdG9yKHMpOwogICAgICAgICAgICAgICAgaWYgKGhhdmVMYXN0KQogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGlmICghay5FcXVhbHMobGFzdCkpCiAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICAgICB5aWVsZCByZXR1cm4gbmV3IEdyb3VwT2ZBZGphY2VudDxUU291cmNlLCBUS2V5PihsaXN0LCBsYXN0KTsKICAgICAgICAgICAgICAgICAgICAgICAgbGlzdCA9IG5ldyBMaXN0PFRTb3VyY2U+KCk7CiAgICAgICAgICAgICAgICAgICAgICAgIGxpc3QuQWRkKHMpOwogICAgICAgICAgICAgICAgICAgICAgICBsYXN0ID0gazsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgZWxzZQogICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgbGlzdC5BZGQocyk7CiAgICAgICAgICAgICAgICAgICAgICAgIGxhc3QgPSBrOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGVsc2UKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBsaXN0LkFkZChzKTsKICAgICAgICAgICAgICAgICAgICBsYXN0ID0gazsKICAgICAgICAgICAgICAgICAgICBoYXZlTGFzdCA9IHRydWU7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGhhdmVMYXN0KQogICAgICAgICAgICAgICAgeWllbGQgcmV0dXJuIG5ldyBHcm91cE9mQWRqYWNlbnQ8VFNvdXJjZSwgVEtleT4obGlzdCwgbGFzdCk7CiAgICAgICAgfQogICAgfQogCnB1YmxpYyBjbGFzcyBUZXN0CnsKICAgICAgICBwdWJsaWMgc3RhdGljIHZvaWQgTWFpbigpCiAgICAgICAgewogICAgICAgICAgIHZhciBsaXN0ID0gbmV3IFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3Q8Rm9vPigpewogICAgICAgICAgICAgICAgbmV3IEZvbygpeyBBID0gMSwgQiA9IDEgfSwKICAgICAgICAgICAgICAgIG5ldyBGb28oKXsgQSA9IDEsIEIgPSAyIH0sCiAgICAgICAgICAgICAgICBuZXcgRm9vKCl7IEEgPSAyLCBCID0gMyB9LAogICAgICAgICAgICAgICAgbmV3IEZvbygpeyBBID0gMiwgQiA9IDQgfSwKICAgICAgICAgICAgICAgIG5ldyBGb28oKXsgQSA9IDEsIEIgPSA1IH0sCiAgICAgICAgICAgICAgICBuZXcgRm9vKCl7IEEgPSAzLCBCID0gNiB9CiAgICAgICAgICAgIH07CiAKICAgICAgICAgICAgdmFyIGdyb3VwcyA9IGxpc3QuR3JvdXBBZGphY2VudCh4ID0+IHguQSk7CiAKICAgICAgICAgICAgZm9yZWFjaCAodmFyIGFiR3JvdXAgaW4gZ3JvdXBzKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBpbnQgYUtleSA9IGFiR3JvdXAuS2V5OwogICAgICAgICAgICAgICAgdmFyIGJMaXN0ID0gc3RyaW5nLkpvaW4oIiwiLCBhYkdyb3VwLlNlbGVjdCh4ID0+IHguQi5Ub1N0cmluZygpKS5Ub0FycmF5KCkpOwogICAgICAgICAgICAgICAgQ29uc29sZS5Xcml0ZUxpbmUoIkEgPSB7MH0sIEJzID0gWyB7MX0gXSAiLCBhS2V5LCBiTGlzdCk7CiAgICAgICAgICAgIH0KICAgICAgICB9Cn0=