考虑我有这个对象:
public class Person
{
public string Name { get; set; }
public string Family { get; set; }
public string Group { get; set; }
}
我想分组一个" Person"根据他们的小组,但我限制了小组数量。
以下是我目前的情况:
var person1=new Person
{
Name = "rfy",
Family = "jhg",
Group = "A"
};
var person2=new Person
{
Name = "rjg",
Family = "fh",
Group = "B"
};
var list = new List<Person> {person1, person2};
var group = list.GroupBy(s => s.Group);
在这种情况下我会有:
"A":{person1,person2,person3}
"B":{person4,Person5,person6}
但我希望每个小组只有两个项目,我希望它是这样的:
"A":{person1,person2}
"B":{person4,Person5}
"A":{person3}
"B":{person6}
答案 0 :(得分:2)
完全是第一组:
[
{ "A": [person1, person2, person3] },
{ "B": [person4, person5, person6] }
]
然后partition it into chunks再次传球。在您的情况下,您希望为分区的每个元素创建一个完整的组对象。这将需要一些SelectMany聪明才能重新创建一个组。 GroupBy该人员组将再次恢复密钥并创建一个新组。
[
[
{ "A": [person1, person2] },
{ "A": [person3] }
],
[
{ "B": [person4, person5] },
{ "B": [person6] }
]
]
在第二轮中,您可以使用SelectMany来展平它。
[
{ "A": [person1, person2] },
{ "A": [person3] },
{ "B": [person4, person5] },
{ "B": [person6] }
]
这是关键部分。 Chunk包含在下面的完整示例中:
var query = people.GroupBy(person => person.Group)
.SelectMany(g => g.Chunk(2))
.SelectMany(g => g.GroupBy(person => person.Group));
这是一个完整的例子。
using System;
using System.Collections.Generic;
using System.Linq;
public class Person
{
public string Name { get; set; }
public string Group { get; set; }
public override string ToString()
{
return string.Format("{0} ({1})", Name, Group);
}
}
public static class Extensions
{
public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunksize)
{
while (source.Any())
{
yield return source.Take(chunksize);
source = source.Skip(chunksize);
}
}
}
class Program
{
static void Main(string[] args)
{
Person[] people = new Person[] {
new Person() { Name = "person1", Group = "A" },
new Person() { Name = "person2", Group = "A" },
new Person() { Name = "person3", Group = "A" },
new Person() { Name = "person4", Group = "B" },
new Person() { Name = "person5", Group = "B" },
new Person() { Name = "person6", Group = "B" }
};
var query = people.GroupBy(person => person.Group)
.SelectMany(g => g.Chunk(2))
.SelectMany(g => g.GroupBy(person => person.Group));
foreach (var group in query)
{
Console.WriteLine(group.Key);
foreach (var item in group)
{
Console.WriteLine(" {0}", item);
}
}
}
}
答案 1 :(得分:0)
好吧,我们似乎应该手动实现例程:
public static partial class EnumerableExtensions {
internal sealed class MyGrouping<TKey, TElement> : IGrouping<TKey, TElement> {
private readonly IEnumerable<TElement> m_Values;
public MyGrouping(TKey key, IEnumerable<TElement> values) {
if (values == null)
throw new ArgumentNullException("values");
Key = key;
m_Values = values;
}
public TKey Key {
get;
}
public IEnumerator<TElement> GetEnumerator() {
return m_Values.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}
public static IEnumerable<IGrouping<TKey, TSource>> GroupByRestricted<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
int size = int.MaxValue) {
if (null == source)
throw new ArgumentNullException("source");
else if (null == keySelector)
throw new ArgumentNullException("keySelector");
else if (size <= 0)
throw new ArgumentOutOfRangeException("size", "size must be positive");
Dictionary<TKey, List<TSource>> dict = new Dictionary<TKey, List<TSource>>();
foreach (var item in source) {
var key = keySelector(item);
List<TSource> list = null;
if (!dict.TryGetValue(key, out list)) {
list = new List<TSource>();
dict.Add(key, list);
}
list.Add(item);
if (list.Count >= size) {
yield return new MyGrouping<TKey, TSource>(key, list.ToArray());
list.Clear();
}
}
foreach (var item in dict.Where(pair => pair.Value.Any()))
yield return new MyGrouping<TKey, TSource>(item.Key, item.Value.ToArray());
}
}
测试
List<Person> test = new List<Person>() {
new Person() { Name = "Person1", Group = "A"},
new Person() { Name = "Person2", Group = "A"},
new Person() { Name = "Person3", Group = "A"},
new Person() { Name = "Person4", Group = "B"},
new Person() { Name = "Person5", Group = "B"},
new Person() { Name = "Person6", Group = "B"},
};
var result = test
.GroupByRestricted(item => item.Group, 2)
.Select(chunk => $"{chunk.Key}: {string.Join("; ", chunk.Select(item => item.Name))}");
Console.WriteLine(string.Join(Environment.NewLine, result));
结果:
A: Person1; Person2
B: Person4; Person5
A: Person3
B: Person6