Как я могу разделить IEnumerable < String > в группы IEnumerable < string > [Дубликат]

EDIT: Я нашел эту удивительную библиотеку, которая заменяет стандартный элемент «select» в HTML с помощью «стильных» элементов: Select2 - https://select2.github.io/ examples.html


В 2011 году вам, возможно, не удалось создать стиль «option», но это 2015 год! Вы можете полностью его стилизовать! Я не понимаю некоторых ответов от 2014 года, говоря, что вы не можете его стилизовать! CSS3 творит чудеса. Я пробовал это в своем собственном коде, и выпадающие «опции» были написаны так же, как и стиль «select»

http://cssdeck.com/labs/styling-select -box-with-css3

Вот пример кода!

select {
    padding:3px;
    margin: 0;
    -webkit-border-radius:4px;
    -moz-border-radius:4px;
    border-radius:4px;
    -webkit-box-shadow: 0 3px 0 #ccc, 0 -1px #fff inset;
    -moz-box-shadow: 0 3px 0 #ccc, 0 -1px #fff inset;
    box-shadow: 0 3px 0 #ccc, 0 -1px #fff inset;
    background: black;
    color:#888;
    border:none;
    outline:none;
    display: inline-block;
    -webkit-appearance:none;
    -moz-appearance:none;
    appearance:none;
    cursor:pointer;
}

29
задан Don Kirkby 13 November 2009 в 23:34
поделиться

8 ответов

var result = sequence.Select((s, i) => new { Value = s, Index = i })
                     .GroupBy(item => item.Index / 3, item => item.Value);

Обратите внимание, что это вернет IEnumerable<IGrouping<int,string>>, который будет функционально похож на то, что вы хотите. Однако, если вам строго необходимо набрать его как IEnumerable<IEnumerable<string>> (чтобы перейти к методу, который ожидает его в C # 3.0, который не поддерживает дисперсию обобщений,), вы должны использовать Enumerable.Cast :

var result = sequence.Select((s, i) => new { Value = s, Index = i })
                     .GroupBy(item => item.Index / 3, item => item.Value)
                     .Cast<IEnumerable<string>>();
29
ответ дан Mehrdad Afshari 13 November 2009 в 23:34
поделиться

Это поздний ответ на эту тему, но вот метод, который не использует временное хранилище:

public static class EnumerableExt
{
    public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> input, int blockSize)
    {
        var enumerator = input.GetEnumerator();

        while (enumerator.MoveNext())
        {
            yield return nextPartition(enumerator, blockSize);
        }
    }

    private static IEnumerable<T> nextPartition<T>(IEnumerator<T> enumerator, int blockSize)
    {
        do
        {
            yield return enumerator.Current;
        }
        while (--blockSize > 0 && enumerator.MoveNext());
    }
}

И некоторый тестовый код:

class Program
{
    static void Main(string[] args)
    {
        var someNumbers = Enumerable.Range(0, 10000);

        foreach (var block in someNumbers.Partition(100))
        {
            Console.WriteLine("\nStart of block.");

            foreach (int number in block)
            {
                Console.Write(number);
                Console.Write(" ");
            }
        }

        Console.WriteLine("\nDone.");
        Console.ReadLine();
    }
}
28
ответ дан Matthew Watson 13 November 2009 в 23:34
поделиться

Вдохновленный реализацией @ dicegiuy30, я хотел создать версию, которая перебирает исходный код только один раз и не создает полный набор результатов в памяти для компенсации. Лучшее, что я придумал, это:

public static IEnumerable<IEnumerable<T>> Split2<T>(this IEnumerable<T> source, int chunkSize) {
    var chunk = new List<T>(chunkSize);
    foreach(var x in source) {
        chunk.Add(x);
        if(chunk.Count <= chunkSize) {
            continue;
        }
        yield return chunk;
        chunk = new List<T>(chunkSize);
    }
    if(chunk.Any()) {
        yield return chunk;
    }
}

Таким образом, я строю каждый блок по требованию. Хотел бы я также избегать List<T> и просто транслировать это, но пока не понял этого.

15
ответ дан Arne Claassen 13 November 2009 в 23:34
поделиться

Я знаю, что на этот вопрос уже получен ответ, но если вы планируете часто использовать кусочки IEnumerables, то я рекомендую создать общий метод расширения, подобный следующему:

public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source, int chunkSize)
{
    return source.Where((x,i) => i % chunkSize == 0).Select((x,i) => source.Skip(i * chunkSize).Take(chunkSize));
}

Затем вы можете использовать sequence.Split(3) для получить то, что вы хотите.

(вы можете назвать это как-то еще как «ломтик» или «кусок», если вам не нравится, что «split» уже был определен для строк. «Split» - это то, что я назвал моим .)

20
ответ дан BrunoSalvino 13 November 2009 в 23:34
поделиться

Мы можем улучшить решение @ Afshari, чтобы сделать действительно ленивую оценку. Мы используем метод GroupAdjacentBy , который выдает группы последовательных элементов с одним и тем же ключом:

sequence
.Select((x, i) => new { Value = x, Index = i })
.GroupAdjacentBy(x=>x.Index/3)
.Select(g=>g.Select(x=>x.Value))

Поскольку группы приводятся один за другим, это решение эффективно работает с длинными или бесконечные последовательности.

2
ответ дан Colonel Panic 13 November 2009 в 23:34
поделиться

Используя Microsoft.Reactive, вы можете сделать это довольно просто, и вы будете проходить только один раз по источнику.

IEnumerable<string> source = new List<string>{"1", "2", "3", "4", "5", "6"};

IEnumerable<IEnumerable<string>> splited = source.ToObservable().Buffer(3).ToEnumerable();
2
ответ дан Martijn Pieters 13 November 2009 в 23:34
поделиться

Ответ Мехрдада Афшари превосходен. Вот метод расширения, который его инкапсулирует:

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

public static class EnumerableExtensions
{
    public static IEnumerable<IEnumerable<T>> GroupsOf<T>(this IEnumerable<T> enumerable, int size)
    {
        return enumerable.Select((v, i) => new {v, i}).GroupBy(x => x.i/size, x => x.v);
    }
}
0
ответ дан Ronnie Overby 13 November 2009 в 23:34
поделиться

Я придумал другой подход. Он хорошо использует итератор while, но результаты кэшируются в памяти, как обычный LINQ, до тех пор, пока они не понадобятся.
Вот код.

public IEnumerable<IEnumerable<T>> Paginate<T>(this IEnumerable<T> source, int pageSize)
{
    List<IEnumerable<T>> pages = new List<IEnumerable<T>>();
    int skipCount = 0;

    while (skipCount * pageSize < source.Count) {
        pages.Add(source.Skip(skipCount * pageSize).Take(pageSize));
        skipCount += 1;
    }

    return pages;
}
0
ответ дан Alex Essilfie 13 November 2009 в 23:34
поделиться
Другие вопросы по тегам:

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