2009-04-15 2 views
9

Я узнал intersperse function от Haskell и искал реализацию в C#.Метод расширения для Enumerable.Intersperse?

Intersperse принимает 2 аргумента, источник IEnumerable <T> и элемент T. Он возвращает IEnumerable с элементом, вставленным между каждым элементом источника.

Одним из возможных вариантов использования, чтобы положить произвольное целое число между списком целых чисел, например:

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

Это общий случай string.join (...).

ответ

12

Что-то другие пропустили: если вы хотите только между пунктами, а также не спереди или сзади , что вам нужно сделать дополнительную проверку:

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

Ах! избили меня! – Daniel

+0

Действительно, секунды в нем ... –

+0

Ваша точка имеет смысл, но я смущен вашим ответом. В вашем примере кажется, что вкрапленный элемент будет первым, что, я думаю, не прав. –

-2

Если вам интересно, как осуществить это, я бы сделал так, как это:

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

То есть один ко многим "ценности" ы –

5

Я закодированы до решения, которое лениво, в духе решений Linq! Другие решения, с которыми я столкнулся, включали перемещение всего списка перед возвратом данных, а затем возврат результирующего списка.

Некоторые из других ответов имеют проверку if на каждой итерации цикла.

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

При использовании GetEnumerator() вы должны Dispose() итератор –

+0

@Marc, спасибо, что указали это! – Daniel

+2

Приятно исключить ветвление в случае большой коллекции. Кстати, это классическая «проблема столба забора», где вам нужны n + 1 или n-1 вещи. 'String.Join()' является наиболее распространенным способом, с которым C# находятся в контакте с ними. –

2

Было бы довольно легко написать:

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