Interleaved与LINQ合并?

我正在尝试使用LINQ。 假设我有两个相同长度的集合:

var first = new string[] { "1", "2", "3" }; var second = new string[] { "a", "b", "c" }; 

我想将这两个集合合并为一个,但是以交错的方式。 因此,结果序列应为:

 "1", "a", "2", "b", "3", "c" 

到目前为止我提出的是Zip ,匿名类型和SelectMany

 var result = first.Zip( second, ( f, s ) => new { F = f, S = s } ) .SelectMany( fs => new string[] { fs.F, fs.S } ); 

有没有人知道用LINQ实现这种交错合并的替代/简单方法?

警告:如果枚举的长度不同,这将跳过尾随元素。 如果您宁愿用空值替换填充较短的集合,请使用Andrew Shepherd的答案 。


您可以编写自己的Interleave扩展方法,就像在此示例中一样 。

 internal static IEnumerable InterleaveEnumerationsOfEqualLength( this IEnumerable first, IEnumerable second) { using (IEnumerator enumerator1 = first.GetEnumerator(), enumerator2 = second.GetEnumerator()) { while (enumerator1.MoveNext() && enumerator2.MoveNext()) { yield return enumerator1.Current; yield return enumerator2.Current; } } } 

通过免除匿名类型,您提供的示例可以更简单:

  var result = first.Zip(second, (f, s) => new[] { f, s }) .SelectMany(f => f); 

接受的答案中给定的实现具有不一致性:
结果序列将始终包含第一个序列的所有元素(因为外部while循环),但如果第二个序列包含更多元素,则不会附加这些元素。

Interleave方法我期望得到的序列包含

  1. 只有’对’(结果序列的长度: min(length_1, length_2) * 2) )或那个
  2. 始终附加较长序列的其余元素(结果序列的长度: length_1 + length_2 )。

以下实现遵循第二种方法。
注意单| 在比较中,避免短路评估。

 public static IEnumerable Interleave ( this IEnumerable first, IEnumerable second) { using (var enumerator1 = first.GetEnumerator()) using (var enumerator2 = second.GetEnumerator()) { bool firstHasMore; bool secondHasMore; while ((firstHasMore = enumerator1.MoveNext()) | (secondHasMore = enumerator2.MoveNext())) { if (firstHasMore) yield return enumerator1.Current; if (secondHasMore) yield return enumerator2.Current; } } } 

您可以根据索引循环并选择数组:

 var result = Enumerable.Range(0, first.Length * 2) .Select(i => (i % 2 == 0 ? first : second)[i / 2]); 
 var result = first.SelectMany( ( f, i ) => new List { f, second[ i ] } );