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;
}
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>>();
Это поздний ответ на эту тему, но вот метод, который не использует временное хранилище:
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();
}
}
Вдохновленный реализацией @ 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>
и просто транслировать это, но пока не понял этого.
Я знаю, что на этот вопрос уже получен ответ, но если вы планируете часто использовать кусочки 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» - это то, что я назвал моим .)
Мы можем улучшить решение @ Afshari, чтобы сделать действительно ленивую оценку. Мы используем метод GroupAdjacentBy
, который выдает группы последовательных элементов с одним и тем же ключом:
sequence
.Select((x, i) => new { Value = x, Index = i })
.GroupAdjacentBy(x=>x.Index/3)
.Select(g=>g.Select(x=>x.Value))
Поскольку группы приводятся один за другим, это решение эффективно работает с длинными или бесконечные последовательности.
Используя Microsoft.Reactive, вы можете сделать это довольно просто, и вы будете проходить только один раз по источнику.
IEnumerable<string> source = new List<string>{"1", "2", "3", "4", "5", "6"};
IEnumerable<IEnumerable<string>> splited = source.ToObservable().Buffer(3).ToEnumerable();
Ответ Мехрдада Афшари превосходен. Вот метод расширения, который его инкапсулирует:
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);
}
}
Я придумал другой подход. Он хорошо использует итератор 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;
}