我想连接两个序列的元素,产生一个包含原始两个元素的所有序列的单个序列,但它们的元素交错。
Concat
LINQ方法可以进行串联,但不需要交织,因此我需要一些特殊的东西。
交织规则如下:
selector
函数,所选元素应为第一个或第二个元素,具体取决于函数的boolean
结果(true
:第一,false
:第二)这是我想要实现的一个实际示例:
var sequence1 = new int[] { 1, 2, 3 };
var sequence2 = new int[] { 11, 12, 13 };
var result = sequence1.ConcatInterleaved(sequence2, (a, b) => (a + b) % 3 == 0);
Console.WriteLine(String.Join("\r\n", result));
预期输出:
1 // Because (1 + 11) % 3 == 0, the first is selected
11 // Because (2 + 11) % 3 != 0, the second is selected
12 // Because (2 + 12) % 3 != 0, the second is selected
2 // Because (2 + 13) % 3 == 0, the first is selected
13 // Because (3 + 13) % 3 != 0, the second is selected
3 // Because sequence2 has no more elements, the next element of sequence1 is selected
我想要一个LINQ解决方案,以便按照内置LINQ方法的精神推迟实际的串联。这是我目前的尝试:
public static IEnumerable<TSource> ConcatInterleaved<TSource>(
this IEnumerable<TSource> source,
IEnumerable<TSource> other,
Func<TSource, TSource, bool> selector)
{
// What to do?
}
更新:我更改了示例,因此它看起来不像是简单的交替交错。
关于selector
函数的说明:该函数不适用于两个序列的预选对,就像它在Zip
方法中一样。这些对不是预定义的。每次选择后,将形成一个新对,其中包含先前选择的被拒绝元素,以及先前选择的序列中的一个新元素。
例如,使用选择器(a, b) => true
,ConcatInterleaved
等效于Concat
:返回sequence1的所有元素,然后返回sequence2的所有元素。另一个示例:使用选择器(a, b) => false
返回sequence2的所有元素,然后返回sequence1的所有元素。
答案 0 :(得分:2)
public static IEnumerable<T> Weave(
this IEnumerable<T> left,
IEnumerable<T> right,
Func<T, T, bool> chooser)
{
using(var leftEnum = left.GetEnumerator())
using(var rightEnum = right.GetEnumerator())
{
bool moreLeft = leftEnum.MoveNext;
bool moreRight = rightEnum.MoveNext;
while(moreLeft && moreRight)
{
if (chooser(leftEnum.Current, rightEnum.Current))
{
yield return leftEnum.Current;
moreLeft = leftEnum.MoveNext();
}
else
{
yield return rightEnum.Current;
moreRight = rightEnum.MoveNext();
}
}
// yield the buffered item, if any
if (moreLeft) yield return leftEnum.Current;
if (moreRight) yield return rightEnum.Current;
// yield any leftover elements
while (leftEnum.MoveNext()) yield return leftEnum.Current;
while (rightEnum.MoveNext()) yield return rightEnum.Current;
}
}