2009-04-15 15 views
9

Aprendí el intersperse function de Haskell, y he estado buscando una implementación en C#.Método de extensión para Enumerable.Intersperse?

Intersperse tiene 2 argumentos, un origen IEnumerable <T> y un elemento T. Devuelve un IEnumerable con un elemento insertado entre cada elemento de la fuente.

Un posible caso de uso es poner un número entero arbitrario en entre una lista de números enteros, por ejemplo:

// returns: {1, 0, 2, 0, 3} 
(List<int>() {1, 2, 3}).Intersperse(0); 

Este es un caso general de string.join (...).

Respuesta

12

Algo que los otros han perdido: si solo deseas que entre los elementos, y no también delante o detrás , que tiene que hacer una comprobación adicional:

public static IEnumerable<T> Intersperse<T>(this IEnumerable<T> source, T element) 
{ 
    bool first = true; 
    foreach (T value in source) 
    { 
     if (!first) yield return element; 
     yield return value; 
     first = false; 
    } 
} 
+0

Ah! ¡golpéame! – Daniel

+0

De hecho, segundos en ello ... –

+0

Tu punto tiene sentido, pero estoy confundido por tu respuesta. Parece en tu ejemplo que el elemento intercalado será lo primero, lo cual no creo que sea correcto. –

-2

Si usted se está preguntando cómo ponerlo en práctica, lo haría así:

public static IEnumerable<T> Intersperse<T>(this IEnumerable<T> collection, T value) 
{ 
    foreach(T item in collection) 
    { 
     yield return item; 
     yield return value; 
    } 

    yield break; 
} 
+2

que tiene de uno a muchos "valor" s –

5

he codificado por una solución que es perezoso, en el espíritu de soluciones de Linq! Otras soluciones que surgieron involucraron atravesar toda la lista antes de devolver los datos, y luego devolver la lista resultante.

Algunas de las otras respuestas tienen una verificación if en cada iteración del ciclo.

public static IEnumerable<T> Intersperse<T>(this IEnumerable<T> source, T element) 
{ 
    using (var enumerator = source.GetEnumerator()) { 
     if (enumerator.MoveNext()) { 
      yield return enumerator.Current; 
      while (enumerator.MoveNext()) { 
       yield return element; 
       yield return enumerator.Current; 
      } 
     } 
    } 
} 
+1

Al usar GetEnumerator(), debe descartar() el iterador –

+0

@Marc, ¡gracias por señalarlo! – Daniel

+2

Es bueno eliminar la ramificación en caso de que la colección sea grande. Por cierto, este es un clásico "Fence Post Problem", donde necesitas n + 1 o n-1 cosas. 'String.Join()' es la forma más común en que los C# ers entran en contacto con estos. –

2

Sería muy fácil escribir:

public static IEnumerable<T> Intersperse<T>(this IEnumerable<T> source, T value) { 
    bool first = true; 
    foreach(T item in source) { 
     if(first) { first = false; } 
     else { yield return value; } 
     yield return item; 
    } 
} 
Cuestiones relacionadas