2009-04-15 8 views
9

J'ai appris le intersperse function de Haskell, et je cherchais une implémentation en C#. Intersperse prend 2 arguments, une source IEnumerable <T> et un élément T. Il renvoie un IEnumerable avec l'élément inséré entre chaque élément de la source.Méthode d'extension pour Enumerable.Intersperse?

Un cas d'utilisation possible est de mettre un entier arbitraire entre une liste d'entiers, par exemple:

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

C'est un cas général de string.join (...).

Répondre

12

Quelque chose que les autres ont manqué: si vous voulez seulement il entre les articles, et non également devant ou derrière , vous devez faire une vérification supplémentaire:

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! bat-moi à ça! – Daniel

+0

En effet, quelques secondes à l'intérieur ... –

+0

Votre point est logique, mais je suis confus par votre réponse. Il semble dans votre exemple que l'élément intercalé passe en premier, ce que je ne pense pas être juste. –

-2

Si vous vous demandez comment la mettre en œuvre, je le ferais comme ceci:

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

Cela a un à plusieurs "valeur" de –

5

J'ai codé une solution qui est paresseux, dans l'esprit des solutions Linq! D'autres solutions que j'ai trouvées consistaient à parcourir toute la liste avant de retourner les données, puis à retourner la liste résultante.

Certaines des autres réponses ont une vérification if à chaque itération de la boucle.

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

Lors de l'utilisation de GetEnumerator(), vous devez Dispose() l'itérateur –

+0

@Marc, merci de le signaler! – Daniel

+2

Il est bon d'éliminer les branches si la collection est grande. En passant, c'est un classique "problème de clôture", où vous avez besoin de n + 1 ou n-1 choses. 'String.Join()' est la manière la plus courante avec laquelle les C# sont en contact. –

2

Il serait assez facile d'écrire:

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