2011-01-11 18 views
6

En Ruby hay un each_cons en Enumerable. Funciona de la siguienteItera y devuelve un conjunto de n elementos consecutivos

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

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

me gustaría hacer esto Cª#. LINQ sería bueno.

A continuación se hace algo similar, pero se realiza un bucle de uno a muchos y también está codificada para devolver sólo dos elementos

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] }); 

Sería bueno si pudiera ser creado como un iterador sobre la matriz original en lugar de tener para crear muchas matrices.

Respuesta

9

intente lo siguiente

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

Esto devolverá un IEnumerable<IEnumerable<int>> con los valores especificados. Puede añadir la expresión .ToArray en cualquier punto de conseguirlo en una matriz si esa es la intención (no se puede saber si eso es whatthe [] significa en rubí)

+0

+1 utilizo declaraciones como esta todo el tiempo –

+0

Niza y I don' En realidad, necesito hacerlo sobre rangos/arreglos no ordenados. No ahora mismo de todos modos. –

+0

Impresionante para 'int'; no es bueno para "elementos n" genéricos. – Jay

0

Aquí está un método de extensión genérica que resultó ser manera de complicado para mi caso de uso actual, pero parece funcionar.

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; 
    } 
} 

aplicación de uso Jay en su lugar. Es MUCHO más rápido. Acabo de dejar este aquí porque se menciona en la respuesta de Jay.

6

Puede crear un método de extensión que alcanza de esta manera:

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); 
     } 
    } 

consumirlo:

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

Si el enumerable es algún tipo de lista vinculada, ¿no sería 'Skip (i)' el más lento en cada iteración? –

+0

@Jonas Esto es realmente extremadamente rápido, entre 150 y 250 veces más rápido que la implementación de cabeza/cola que había estado utilizando en el método de extensión anterior que publicó, y el uso de 'LinkedList ' realmente lo hace mucho más rápido. – Jay

+0

¿Cómo lo midiste? Hice algunas pruebas simples de "cronómetro" con listas de 100000 números y, aunque la mía fue más lenta, solo 12ms contra 15ms. –

Cuestiones relacionadas