2011-01-11 2 views
6

В Ruby есть each_cons на Enumerable. Он работает как этотИтерационные и возвратные массивы последовательных n элементов

(1..5).each_cons(3) {|n| p n} 

[1, 2, 3]
[2, 3, 4]
[3, 4, 5]

Я хотел бы это сделать в C#. LINQ было бы неплохо.

Следующая делает что-то подобное, но это петлями один ко многим, и это также жёстко возвращать только два элемента

var ints = new int[] { 1, 2, 3, 4, 5, 6, 7 }; 
var cons = ints.Select((o, i) => 
      new int[]{ ints[i], i == ints.Length - 1 ? 0 : ints[i + 1] }); 

Было бы хорошо, если бы он мог быть создан в качестве итератора над исходного массива, вместо того, для создания множества массивов.

ответ

9

Попробуйте следующее

var ints = Enumerable.Range(1, 3).Select(x => Enumerable.Range(x, 3)); 

Это возвращает IEnumerable<IEnumerable<int>> с заданными значениями. Вы можете добавить выражение .ToArray в любой момент, чтобы получить его в массив, если это намерение (не могу сказать, если это whatthe [] означает в рубин)

+0

+1 Я использую заявления, как это все время –

+0

приятно, и я не» t действительно нужно делать это по неупорядоченным диапазонам/массивам. Не сейчас. –

+0

Awesome for 'int'; не подходит для общих «n элементов». – Jay

0

Вот общий метод расширения, который оказался путь к сложным для мой текущий вариант использования, но он, похоже, работает.

static class EnumerableExtension 
{ 
    public static IEnumerable<IEnumerable<T>> EachCons<T>(this IEnumerable<T> sequence, int cons) 
    { 
     for (IEnumerable<T> head = sequence.Take(cons), tail = sequence.Skip(1); 
      head.Count() == cons; head = tail.Take(cons), tail = tail.Skip(1)) 
      yield return head; 
    } 
} 

Используйте вместо реализации Джей. Это намного быстрее. Я просто оставил это здесь, потому что это упоминается в ответе Джея.

6

Вы можете создать метод расширения, который достигает его таким образом:

public static IEnumerable<IEnumerable<T>> each_cons<T>(this IEnumerable<T> enumerable, int length) 
    { 
     for (int i = 0; i < enumerable.Count() - length + 1; i++) 
     { 
      yield return enumerable.Skip(i).Take(length); 
     } 
    } 

употребить:

var ints = Enumerable.Range(1, 7).each_cons(3); 
+0

Если перечислимый - это какой-то связанный список, не будет ли 'Skip (i)' становиться медленнее каждой итерацией? –

+0

@Jonas Это на самом деле очень быстро - от 150 до 250 раз быстрее, чем реализация головы/хвоста, которую вы использовали в предыдущем методе расширения, который вы опубликовали, и использование 'LinkedList ' фактически делает его значительно быстрее. – Jay

+0

Как вы это измерили? Я сделал несколько простых тестов «StopWatch» со списками из 100 000 номеров, и хотя мой был медленнее, он составлял всего 12 мс против 15 мс. –

Смежные вопросы