我想知道是否有 LINQ 運算子來執行此操作:
var one = new[] { "A", "B", "C" };
var two = new[] { "A", "B", "C", "D" };
var combined = new [] { one, two };
var result = Operator(combined);
Console.WriteLine(result.Should().BeEquivalentTo(new [] { "A", "A", "B", "B", "C", "C", null, "D" }));
如果很短,它應該就像每個序列都是矩陣中的一行一樣。之后,它應該:
- 轉置矩陣(旋轉它)
- 它應該推送矩陣中的每個“單元格”,回傳相應的專案,如果單元格為空,則回傳默認值。
我的意思是,以圖形方式:
A, B, C
A, B, C, D
<Transpose>
A, A
B, B
C, C
D
result => A, A, B, B, C, C, D, null
注意
Operator應該努力IEnumerable<IEnumerable<T>>
如您所見,Operator我感興趣的使用combined,因此它接受應該IEnumerable<IEnumerable<T>>(如SelectMany)。
uj5u.com熱心網友回復:
跟上您不斷變化的規格有點困難。最初,它是一對字串陣列。我在答案中將其更改為一對陣列T。
然后你在評論中寫道“哦,不,我的意思是 N 個序列”。最后,在閱讀之后,我注意到您已更新您的問題以詢問表示為的 N 個集合IEnumerable<T>。
同時,我指出我的原始答案適用于 N 個陣列,而且變化很小。所以,這里是:
對于 N 個陣列
我使用params關鍵字來消除對組合變數的需要。params關鍵字會將方法的部分或全部引數組合成一個陣列。
這是一個可以采用 N 個陣列的方法:
public static IEnumerable<T> KnitArrays<T>(params T[][] arrays)
{
var maxLen = (from array in arrays select array.Length).Max();
for (var i = 0; i < maxLen; i )
{
foreach( var array in arrays)
{
yield return array.Length > i ? array[i] : default(T);
}
}
}
這與原始答案的邏輯幾乎相同。測驗代碼看起來也一樣:
var one = new[] { "A1", "B1", "C1" };
var two = new[] { "A2", "B2", "C2", "D2" };
var three = new[] { "A3", "B3" };
var knittedArray = KnitArrays(one, two, three);
List<string> result = knittedArray.ToList();
WriteCollectionContents(result);
哪里WriteCollectionContents吐出集合的內容。在這種情況下:
"A1", "A2", "A3", "B1", "B2", "B3", "C1", "C2", null, null, "D2", null,
對于 N 個串列和/或陣列
事實證明,相同的基本代碼可以使用IList<T>,即List<T>和T[]:
public static IEnumerable<T> KnitILists<T>(params IList<T>[] ilists)
{
var maxLen = (from ilist in ilists select ilist.Count).Max();
for (var i = 0; i < maxLen; i )
{
foreach (var ilist in ilists)
{
yield return ilist.Count > i ? ilist[i] : default(T);
}
}
}
這個測驗代碼看起來也很相似——盡管注意混合或陣列和串列:
var one = new[] { "A1", "B1", "C1" };
var two = new[] { "A2", "B2", "C2", "D2" };
var list3 = new List<string> { "A3", "B3" };
var knittedLists = KnitILists(one, two, list3);
result = knittedLists.ToList();
WriteCollectionContents(result);
結果完全相同:
"A1", "A2", "A3", "B1", "B2", "B3", "C1", "C2", null, null, "D2", null,
它使用的原因IList<T>是該介面具有Count屬性和Item索引器。如果你去屬性停留,但你失去了ICollection<T>索引器。CountItem
一旦你到達IEnumerable<T>,Count屬性和Item索引器都消失了。對 an 唯一能做的IEnumerable就是遍歷它。因此,邏輯需要非常不同。
我可能會想出一個解決方案。但是,它可能看起來與@gertarnold 的答案非常相似。
我正在尋找你即將發表的評論的前言,關于你真正打算如何使用多維陣列。
原始答案如下
像這樣的東西怎么樣:
public static IEnumerable<T> KnitArrays<T>(T[] first, T[] second)
{
var maxLen = Math.Max(first.Length, second.Length);
for (var i = 0; i < maxLen; i )
{
yield return first.Length > i ? first[i] : default(T);
yield return second.Length > i ? second[i] : default(T);
}
}
使用以下方法進行測驗:
var one = new[] { "A", "B", "C" };
var two = new[] { "A", "B", "C", "D" };
var knittedArray = KnitArrays(one, two);
List<string> result = knittedArray.ToList();
產生一個看起來像你所問的串列。請注意,我只是回傳一個非物化的 IEnumerable,因為您詢問的是 LINQ。
uj5u.com熱心網友回復:
為了使結果獨立于陣列的數量,函式應該回圈遍歷所有陣列并繼續回傳,直到所有列舉都用完:
public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> source)
{
var enumerators = source.Select(e => e.GetEnumerator()).ToArray();
try
{
var next = false;
do
{
var results = enumerators.Select(enr =>
{
if (enr.MoveNext())
{
return enr.Current;
}
return default;
}).ToList();
next = results.Any(e => !Equals(default, e));
if (next)
{
yield return results;
}
}
while (next);
}
finally
{
Array.ForEach(enumerators, e => e.Dispose());
}
}
現在您可以使用任意數量的陣列:
var one = new[] { "A", "B", "C" };
var two = new[] { "A", "B", "C", "D" };
var three = new[] { "U", "V","W", "X", "Y", "Z" };
var combined = new[] { one, three, two };
var result = combined.Transpose().SelectMany(e => e).ToList();
這將導致
"A","U","A","B","V","B","C","W","C",null,"X","D",null,"Y",null,null,"Z",null
過濾空值很簡單。
(感謝這個基本思想的答案,但只適用于等長的陣列)。
uj5u.com熱心網友回復:
嘗試這個
var result = Enumerable.Range(0, Math.Max(one.Count(), two.Count()))
.SelectMany(n => new[] { one.ElementAtOrDefault(n), two.ElementAtOrDefault(n) });
結果
["A","A","B","B","C","C",null,"D"]
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/428917.html
