如何在linq中组合条件

时间:2018-06-13 12:53:25

标签: c# linq group-by

考虑我有这个对象:

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}

2 个答案:

答案 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