2009-04-15 26 views
9

Ho appreso il intersperse function da Haskell e ho cercato un'implementazione in C#.Metodo di estensione per Enumerable.Intersperse?

L'intervallo prende 2 argomenti, un oggetto IEnumerable <T> e un elemento T. Restituisce un oggetto IEnumerable con elemento inserito tra ogni elemento di origine.

Una possibile caso d'uso è quello di mettere un intero arbitrario tra un elenco di numeri interi, ad esempio:

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

Questo è un caso generale di string.join (...).

risposta

12

qualcosa che gli altri hanno perso: se desideri solo in tra gli elementi, e non anche davanti o dietro , è necessario fare un controllo aggiuntivo:

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! bastonatemi! – Daniel

+0

Infatti, secondi in esso ... –

+0

Il tuo punto ha senso, ma sono confuso dalla tua risposta. Sembra nel tuo esempio che l'elemento intercalato verrà prima, cosa che non penso sia giusta. –

-2

Se vi state chiedendo come implementarlo, lo farei in questo modo:

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

che ha uno a molti "valore" s –

5

ho codificato una soluzione che è pigro, nello spirito di soluzioni Linq! Altre soluzioni che ho trovato coinvolte attraversano l'intera lista prima di restituire i dati, e quindi restituire la lista risultante.

Alcune delle altre risposte hanno un controllo se su ogni iterazione 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

Quando si utilizza GetEnumerator(), si dovrebbe eliminare() l'iteratore –

+0

@Marc, grazie per averlo indicato! – Daniel

+2

È utile eliminare la ramificazione nel caso in cui la raccolta sia ampia. A proposito, questo è un classico "Problema Post Fence", in cui hai bisogno di n + 1 o n-1 cose. 'String.Join()' è il modo più comune in cui i C#er entrano in contatto con questi. –

2

Sarebbe abbastanza facile da scrivere:

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