Как группировать с условием в linq - PullRequest
0 голосов
/ 13 июня 2018

Считайте, что у меня есть этот объект:

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 голосов
/ 13 июня 2018

Первая группа целиком:

[
    { "A": [person1, person2, person3] },
    { "B": [person4, person5, person6] }
]

Затем разбить его на куски за второй проход.В вашем случае вы хотите создать целый объект группы для каждого элемента раздела.Это потребует некоторого умения SelectMany для воссоздания группы.Группа. Группа человека снова восстановит ключ и создаст новую группу.

[
    [
        { "A": [person1, person2] },
        { "A": [person3] }
    ],
    [
        { "B": [person4, person5] },
        { "B": [person6] }
    ]
]

А также во втором проходе вы можете использовать SelectMany , чтобы сгладить его.

[
    { "A": [person1, person2] },
    { "A": [person3] },
    { "B": [person4, person5] },
    { "B": [person6] }
]

Вот критическая часть.Чанк включен в полный пример ниже:

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);
            }
        }
    }
}
0 голосов
/ 13 июня 2018

Что ж, похоже, мы должны реализовать процедуру вручную:

  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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...