从这个Q: How to split an array to 2 arrays with odd and even indices respectively?
我已经使用这种方法将数组分成2个分别具有奇数和偶数索引的数组:
int[] a = new int[] { 1, 3, 7, 8 };
int[] aEven = a.Where((x, i) => i % 2 == 0).ToArray();
int[] aOdd = a.Where((x, i) => i % 2 != 0).ToArray();
这导致2个阵列:
aEven : {1, 7}
aOdd : {3, 8}
如何以优雅的方式将aEven
/ aOdd
合并为与原始a
数组相同?
注意:我没有更改aEven
/ aOdd
数组,并且保证两个数组都具有相同的长度。
aEven
/ aOdd
输入所需的输出是:
{ 1, 3, 7, 8 };
答案 0 :(得分:4)
执行此操作的一种方法是将Enumerable.Zip
和Enumerable.Aggregate
以及稍微混合组合在一起。请注意,此仍然使用循环。
var aList = aEven.Zip(aOdd, (even, odd) => new {even, odd})
.Aggregate(new List<int>(aEven.Length + aOdd.Length),
(list, z) =>
{
list.Add(z.even);
list.Add(z.odd);
return list;
});
if (aEven.Length != aOdd.Length)
aList.Add(aEven[aEven.Length-1]);
var aOutput = aList.ToArray();
for (var i = 0; i < aOutput.Length; ++i)
Console.WriteLine($"aOutput[{i}] ==> {aOutput[i]} == {a[i]} <== a[{i}]");
这仅适用于你的场景但是(拆分然后通过奇数/偶数索引恢复数组,假设'子阵列'的顺序有一直保持)。
结果数组将具有相同的大小(原始数组具有偶数项)或偶数数组将具有一个额外项(原始数组具有奇数项)。在后一种情况下,额外项目将被Zip
删除,需要手动计算。这不适用于通过其他方式计算两个子阵列的其他场景。
你也可以在没有中间列表的情况下使用预先分配的数组,但你必须跟踪LINQ调用之外的索引(我不喜欢这样):
var index = 0;
var aOutput = aEven.Zip(aOdd, (even, odd) => new {even, odd})
.Aggregate(new int[aEven.Length + aOdd.Length],
(arr, z) =>
{
arr[index++] = z.even;
arr[index++] = z.odd;
return arr;
});
if (aEven.Length != aOdd.Length)
aOutput[index] = aEven[aEven.Length-1];
另一种方法是使用Zip
,SelectMany
和Concat
的组合(以说明最后一项):
var aOutput = aEven.Zip(aOdd, (even, odd) => new[]{ even, odd })
.SelectMany(z => z)
.Concat(aEven.Length == aOdd.Length ? new int[0] : new []{ aEven[aEven.Length - 1] })
.ToArray();
简单的循环仍然可能是最简单的解决方案。
答案 1 :(得分:2)
只需使用for
循环。它不会创建所有这些元组的中间数组,同时具有可比性,并且需要相同数量的代码。
int[] Merge(int[] evenItems, int[] oddItems)
{
var itemsCount = evenItems.Length + oddItems.Length;
var result = new int[itemsCount];
for (var i = 0; i < itemsCount; i++)
{
var sourceIndex = Math.DivRem(i, 2, out var remainder);
var source = remainder == 0 ? evenItems : oddItems;
result[i] = source[sourceIndex];
}
return result;
}
答案 2 :(得分:1)
创建InterlockWith
扩展方法,是的,循环无法逃脱:
public static IEnumerable<T> InterlockWith<T>(this IEnumerable<T> seq1, IEnumerable<T> seq2)
{
Tuple<T[], int>[] metaSequences = new Tuple<T[], int>[2];
metaSequences[0] = Tuple.Create(seq1.ToArray(), seq1.Count());
metaSequences[1] = Tuple.Create(seq2.ToArray(), seq2.Count());
var orderedMetas = metaSequences.OrderBy(x => x.Item2).ToArray();
for (int i = 0; i < orderedMetas[0].Item2; i++)
{
yield return metaSequences[0].Item1[i];
yield return metaSequences[1].Item1[i];
}
var remainingItems = orderedMetas[1].Item1.Skip(orderedMetas[0].Item2);
foreach (var item in remainingItems)
{
yield return item;
}
}
您可以通过以下方式调用结果集来获取结果集:
a = aEven.InterlockWith(aOdd).ToArray();
答案 3 :(得分:1)
var merged = evens
.Zip(odds, (even, odd) => new [] {even, odd})
.SelectMany(pair => pair)
.Concat(evens.Skip(odds.Length))
.ToArray();
答案 4 :(得分:-1)
首先你可以使用Concat合并它们,然后如果你想要对reslt进行排序,你可以使用OrderBy:
aEven.Concat(aOdd).OrderBy(b => b).ToArray();