这里有一些其他的方法来做到这一点。它们都应该具有相当的性能,没有一个需要首先完整地遍历输入序列。它们都正确处理空输入和单项输入。
多选
我喜欢的方式是这样的:
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);
它们都是等效的:对于每个item,创建一个新序列{ delimiter, item },并使用SelectMany
将它们连接在一起。之后,跳过第一个分隔符——它只是一个额外的分隔符。与其他选项相比,我更喜欢这些选项的唯一原因是它们可以在紧要关头内联使用,而无需编写额外的函数。
以下是其他一些实现(注意我称它们为Delimit
not 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
基于答案的答案,但处理第一个元素的方法不同(我认为更干净):
public static IEnumerable<T> Delimit3a <T> (this IEnumerable<T> source, T delimiter) {
foreach (T item in source.Take(1)) // protects agains empty source
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 ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]