Разделите набор на, и' расстается с LINQ?

121
задан jpaugh 20 May 2017 в 19:34
поделиться

8 ответов

Чистый linq и простое решение как показано ниже.

static class LinqExtensions
{
    public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> list, int parts)
    {
        int i = 0;
        var splits = from item in list
                     group item by i++ % parts into part
                     select part.AsEnumerable();
        return splits;
    }
}
126
ответ дан 24 November 2019 в 01:30
поделиться

Это - мой код, хороший и короткий.

 <Extension()> Public Function Chunk(Of T)(ByVal this As IList(Of T), ByVal size As Integer) As List(Of List(Of T))
     Dim result As New List(Of List(Of T))
     For i = 0 To CInt(Math.Ceiling(this.Count / size)) - 1
         result.Add(New List(Of T)(this.GetRange(i * size, Math.Min(size, this.Count - (i * size)))))
     Next
     Return result
 End Function
0
ответ дан 24 November 2019 в 01:30
поделиться
int[] items = new int[] { 0,1,2,3,4,5,6,7,8,9, 10 };

int itemIndex = 0;
int groupSize = 2;
int nextGroup = groupSize;

var seqItems = from aItem in items
               group aItem by 
                            (itemIndex++ < nextGroup) 
                            ? 
                            nextGroup / groupSize
                            :
                            (nextGroup += groupSize) / groupSize
                            into itemGroup
               select itemGroup.AsEnumerable();
-1
ответ дан 24 November 2019 в 01:30
поделиться

Если порядок в этих частях не очень важен, можно попробовать это:

int[] array = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int n = 3;

var result =
   array.Select((value, index) => new { Value = value, Index = index }).GroupBy(i => i.Index % n, i => i.Value);

// or
var result2 =
   from i in array.Select((value, index) => new { Value = value, Index = index })
   group i.Value by i.Index % n into g
   select g;

Однако они не могут быть брошены к IEnumerable< IEnumerable< int> > некоторой причиной...

0
ответ дан 24 November 2019 в 01:30
поделиться

РЕДАКТИРОВАНИЕ: Хорошо, похоже, что я неправильно читал вопрос. Я считал его как "части длины n", а не "n части". Doh! Рассмотрение ответа удаления...

(Исходный ответ)

я не полагаю, что существует встроенный способ разделить, хотя я намереваюсь записать один в моем наборе дополнений к LINQ к Объектам. Marc Gravell имеет реализация здесь , хотя я, вероятно, изменил бы ее для возврата представления только для чтения:

public static IEnumerable<IEnumerable<T>> Partition<T>
    (this IEnumerable<T> source, int size)
{
    T[] array = null;
    int count = 0;
    foreach (T item in source)
    {
        if (array == null)
        {
            array = new T[size];
        }
        array[count] = item;
        count++;
        if (count == size)
        {
            yield return new ReadOnlyCollection<T>(array);
            array = null;
            count = 0;
        }
    }
    if (array != null)
    {             
        Array.Resize(ref array, count);
        yield return new ReadOnlyCollection<T>(array);
    }
}
58
ответ дан 24 November 2019 в 01:30
поделиться

I use this:

public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> instance, int partitionSize)
{
    return instance
        .Select((value, index) => new { Index = index, Value = value })
        .GroupBy(i => i.Index / partitionSize)
        .Select(i => i.Select(i2 => i2.Value));
}
4
ответ дан 24 November 2019 в 01:30
поделиться

Кортежи можно использовать в качестве словарных ключей, поскольку они являются неизменяемыми, но нельзя использовать списки. Например:

d = {(1, 2): 'a', (3, 8, 1): 'b'}  # Valid.
d = {[1, 2]: 'a', [3, 8, 1]: 'b'}  # Error.
-121--3464956-

Да, sqrt (int) в тесте не может быть применен к (double)

Переименуйте свою функцию с другим именем, если вы хотите вызвать Math.sqrt:

private static double mysqrt(int n)
{
    return sqrt(1.0 * n);
}
-121--3286579-

i Плохо только то, что это не совсем потоковая передача. Это не проблема, если вы работаете с несколькими элементами в вашей последовательности. Мне нужно было новое решение, когда я начал работать с 100 000 + элементов в моей последовательности.

Следующее решение намного сложнее (и больше кода!), но оно очень эффективно.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace LuvDaSun.Linq
{
    public static class EnumerableExtensions
    {
        public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> enumerable, int partitionSize)
        {
            /*
            return enumerable
                .Select((item, index) => new { Item = item, Index = index, })
                .GroupBy(item => item.Index / partitionSize)
                .Select(group => group.Select(item => item.Item)                )
                ;
            */

            return new PartitioningEnumerable<T>(enumerable, partitionSize);
        }

    }


    class PartitioningEnumerable<T> : IEnumerable<IEnumerable<T>>
    {
        IEnumerable<T> _enumerable;
        int _partitionSize;
        public PartitioningEnumerable(IEnumerable<T> enumerable, int partitionSize)
        {
            _enumerable = enumerable;
            _partitionSize = partitionSize;
        }

        public IEnumerator<IEnumerable<T>> GetEnumerator()
        {
            return new PartitioningEnumerator<T>(_enumerable.GetEnumerator(), _partitionSize);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }


    class PartitioningEnumerator<T> : IEnumerator<IEnumerable<T>>
    {
        IEnumerator<T> _enumerator;
        int _partitionSize;
        public PartitioningEnumerator(IEnumerator<T> enumerator, int partitionSize)
        {
            _enumerator = enumerator;
            _partitionSize = partitionSize;
        }

        public void Dispose()
        {
            _enumerator.Dispose();
        }

        IEnumerable<T> _current;
        public IEnumerable<T> Current
        {
            get { return _current; }
        }
        object IEnumerator.Current
        {
            get { return _current; }
        }

        public void Reset()
        {
            _current = null;
            _enumerator.Reset();
        }

        public bool MoveNext()
        {
            bool result;

            if (_enumerator.MoveNext())
            {
                _current = new PartitionEnumerable<T>(_enumerator, _partitionSize);
                result = true;
            }
            else
            {
                _current = null;
                result = false;
            }

            return result;
        }

    }



    class PartitionEnumerable<T> : IEnumerable<T>
    {
        IEnumerator<T> _enumerator;
        int _partitionSize;
        public PartitionEnumerable(IEnumerator<T> enumerator, int partitionSize)
        {
            _enumerator = enumerator;
            _partitionSize = partitionSize;
        }

        public IEnumerator<T> GetEnumerator()
        {
            return new PartitionEnumerator<T>(_enumerator, _partitionSize);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }


    class PartitionEnumerator<T> : IEnumerator<T>
    {
        IEnumerator<T> _enumerator;
        int _partitionSize;
        int _count;
        public PartitionEnumerator(IEnumerator<T> enumerator, int partitionSize)
        {
            _enumerator = enumerator;
            _partitionSize = partitionSize;
        }

        public void Dispose()
        {
        }

        public T Current
        {
            get { return _enumerator.Current; }
        }
        object IEnumerator.Current
        {
            get { return _enumerator.Current; }
        }
        public void Reset()
        {
            if (_count > 0) throw new InvalidOperationException();
        }

        public bool MoveNext()
        {
            bool result;

            if (_count < _partitionSize)
            {
                if (_count > 0)
                {
                    result = _enumerator.MoveNext();
                }
                else
                {
                    result = true;
                }
                _count++;
            }
            else
            {
                result = false;
            }

            return result;
        }

    }
}

Наслаждайтесь!

6
ответ дан 24 November 2019 в 01:30
поделиться

Хорошо, я брошу свою шляпу на ринг. Преимущества моего алгоритма:

  1. Нет дорогих операторов умножения, деления или модуляции
  2. Все операции O(1) (см. примечание ниже)
  3. Работает для источника IEnumerable<> (не нужно свойство Count)
  4. Простой

Код:

public static IEnumerable<IEnumerable<T>>
  Section<T>(this IEnumerable<T> source, int length)
{
  if (length <= 0)
    throw new ArgumentOutOfRangeException("length");

  var section = new List<T>(length);

  foreach (var item in source)
  {
    section.Add(item);

    if (section.Count == length)
    {
      yield return section.AsReadOnly();
      section = new List<T>(length);
    }
  }

  if (section.Count > 0)
    yield return section.AsReadOnly();
}

Как указано в комментариях ниже, этот подход на самом деле не решает исходный вопрос, который просил фиксированное количество секций примерно одинаковой длины. Тем не менее, вы можете использовать мой подход для решения исходного вопроса, назвав его так:

myEnum.Section(myEnum.Count() / number_of_sections + 1)

При таком использовании подход больше не является O(1), поскольку операция Count() является O(N).

24
ответ дан 24 November 2019 в 01:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: