以下是其他实现方式。它们都应该具有良好的性能,无需首先对输入序列进行完整遍历。所有这些方法都可以正确处理空输入和单个项目输入。
SelectMany
我喜欢的方式是:
public static IEnumerable<T> Intersperse <T> (this IEnumerable<T> source, T delimiter) =>
source.SelectMany((item) => Enumerable.Empty<T>().Append(delimiter).Append(item)).Skip(1);
或者,另一种选择:
public static IEnumerable<T> Intersperse <T> (this IEnumerable<T> source, T delimiter) =>
source.SelectMany((item) => new T[] { delimiter, item }).Skip(1);
它们都是等效的:对于每个项,创建一个新序列{ delimiter,item },并使用SelectMany
将它们全部连接在一起。之后,跳过第一个分隔符--它只是多余的。我喜欢这些选项的唯一原因是它们可以在紧急情况下内联使用,而不必编写额外的函数。
这里有几个其他实现(请注意,我称它们为Delimit
而不是Intersperse
):
聚合
虽然我认为它很笨重,但可以使用Aggregate
来完成:
public static IEnumerable<T> Delimit2a <T> (this IEnumerable<T> source, T delimiter) =>
source.Aggregate(Enumerable.Empty<T>(), (delimited, item) => delimited.Append(delimiter).Append(item)).Skip(1);
public static IEnumerable<T> Delimit2b <T> (this IEnumerable<T> source, T delimiter) =>
source.Aggregate(null as IEnumerable<T>, (delimited, item) => (delimited?.Append(delimiter) ?? Enumerable.Empty<T>()).Append(item)) ?? Enumerable.Empty<T>();
2b 可能不值得考虑:它省略了 Skip(1)
,但代价是很多额外的冗长和分支。
yield return
这些与其他基于 yield return
的答案类似,但处理第一个元素的方法不同(在我看来更加简洁):
public static IEnumerable<T> Delimit3a <T> (this IEnumerable<T> source, T delimiter) {
foreach (T item in source.Take(1))
yield return item;
foreach (T item in source.Skip(1)) {
yield return delimiter;
yield return item;
}
}
public static IEnumerable<T> Delimit3b <T> (this IEnumerable<T> source, T delimiter) {
static IEnumerable<U> Helper<U> (IEnumerable<U> source, U delimiter) {
foreach (U item in source) {
yield return delimiter;
yield return item;
}
}
return Helper(source, delimiter).Skip(1);
}
测试代码 / 示例
这里有一个可运行的示例,包含测试代码在这里。测试部分:
public static void Main () {
foreach (int count in new int[] { 11, 2, 1, 0 }) {
p( Enumerable.Range(10, count).Delimit1a(-1) );
p( Enumerable.Range(10, count).Delimit1b(-1) );
p( Enumerable.Range(10, count).Delimit2a(-1) );
p( Enumerable.Range(10, count).Delimit2b(-1) );
p( Enumerable.Range(10, count).Delimit3a(-1) );
p( Enumerable.Range(10, count).Delimit3b(-1) );
}
}
static void p <T> (IEnumerable<T> e) =>
Console.WriteLine($"[ {string.Join(", ", e)} ]");
输出以下内容:
[ 10, -1, 11, -1, 12, -1, 13, -1, 14, -1, 15, -1, 16, -1, 17, -1, 18, -1, 19, -1, 20 ]
[ 10, -1, 11, -1, 12, -1, 13, -1, 14, -1, 15, -1, 16, -1, 17, -1, 18, -1, 19, -1, 20 ]
[ 10, -1, 11, -1, 12, -1, 13, -1, 14, -1, 15, -1, 16, -1, 17, -1, 18, -1, 19, -1, 20 ]
[ 10, -1, 11, -1, 12, -1, 13, -1, 14, -1, 15, -1, 16, -1, 17, -1, 18, -1, 19, -1, 20 ]
[ 10, -1, 11, -1, 12, -1, 13, -1, 14, -1, 15, -1, 16, -1, 17, -1, 18, -1, 19, -1, 20 ]
[ 10, -1, 11, -1, 12, -1, 13, -1, 14, -1, 15, -1, 16, -1, 17, -1, 18, -1, 19, -1, 20 ]
[ 10, -1, 11 ]
[ 10, -1, 11 ]
[ 10, -1, 11 ]
[ 10, -1, 11 ]
[ 10, -1, 11 ]
[ 10, -1, 11 ]
[ 10 ]
[ 10 ]
[ 10 ]
[ 10 ]
[ 10 ]
[ 10 ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]