[英]How to combine more than two generic lists in C# Zip?
我有三個(可能有超過 3-4 個通用列表,但在本例中讓 3 個)通用列表。
List<string> list1
List<string> list2
List<string> list3
所有列表都具有相同數量的元素(相同的計數)。
我用它來將兩個列表與 ZIP 結合起來:
var result = list1.Zip(list2, (a, b) => new {
test1 = f,
test2 = b
}
我將其用於foreach
語句,以避免foreach
每個列表,例如
foreach(var item in result){
Console.WriteLine(item.test1 + " " + item.test2);
}
如何將 simmilary 與 Zip 用於三個列表?
謝謝
編輯:
我想要:
List<string> list1 = new List<string>{"test", "otherTest"};
List<string> list2 = new List<string>{"item", "otherItem"};
List<string> list3 = new List<string>{"value", "otherValue"};
ZIP后(我不知道方法),我想要結果(在VS2010調試模式下)
[0] { a = {"test"},
b = {"item"},
c = {"value"}
}
[1] { a = {"otherTest"},
b = {"otherItem"},
c = {"otherValue"}
}
怎么做 ?
對我來說最明顯的方法是使用Zip
兩次。
例如,
var results = l1.Zip(l2, (x, y) => x + y).Zip(l3, (x, y) => x + y);
將組合(添加)三個List<int>
對象的元素。
更新:
您可以定義一個新的擴展方法,它的作用類似於帶有三個IEnumerable
的Zip
,如下所示:
public static class MyFunkyExtensions
{
public static IEnumerable<TResult> ZipThree<T1, T2, T3, TResult>(
this IEnumerable<T1> source,
IEnumerable<T2> second,
IEnumerable<T3> third,
Func<T1, T2, T3, TResult> func)
{
using (var e1 = source.GetEnumerator())
using (var e2 = second.GetEnumerator())
using (var e3 = third.GetEnumerator())
{
while (e1.MoveNext() && e2.MoveNext() && e3.MoveNext())
yield return func(e1.Current, e2.Current, e3.Current);
}
}
}
用法(在與上述相同的上下文中)現在變為:
var results = l1.ZipThree(l2, l3, (x, y, z) => x + y + z);
同樣,您現在可以將三個列表與:
var results = list1.ZipThree(list2, list3, (a, b, c) => new { a, b, c });
我知道還有另一個非常有趣的解決方案。 從教育的角度來看,這很有趣,但如果需要執行壓縮不同數量的列表很多,那么它也可能有用。
此方法覆蓋 .NET 的 LINQ SelectMany
函數,當您使用 LINQ 的查詢語法時,該函數由約定采用。 標准SelectMany
實現執行笛卡爾積。 被覆蓋的可以改為進行壓縮。 實際的實現可能是:
static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source,
Func<TSource, IEnumerable<TCollection>> selector, Func<TSource, TCollection, TResult> select)
{
using (var e1 = source.GetEnumerator())
using (var e2 = selector(default(TSource)).GetEnumerator())
while (true)
if (e1.MoveNext() && e2.MoveNext())
yield return select(e1.Current, e2.Current);
else
yield break;
}
它看起來有點嚇人,但它是一種壓縮邏輯,如果編寫一次,可以在很多地方使用,並且客戶端的代碼看起來很不錯 - 您可以使用標准 LINQ 查詢語法壓縮任意數量的IEnumerable<T>
:
var titles = new string[] { "Analyst", "Consultant", "Supervisor"};
var names = new string[] { "Adam", "Eve", "Michelle" };
var surnames = new string[] { "First", "Second", "Third" };
var results =
from title in titles
from name in names
from surname in surnames
select $"{ title } { name } { surname }";
如果然后執行:
foreach (var result in results)
Console.WriteLine(result);
你會得到:
Analyst Adam First
Consultant Eve Second
Supervisor Michelle Third
你應該在你的類中保持這個擴展是私有的,否則你會從根本上改變周圍代碼的行為。 此外,新類型將非常有用,因此它不會與 IEnumerables 的標准 LINQ 行為發生沖突。
出於教育目的,我使用此擴展方法創建了一個小型 c# 項目 + 一些好處: https : //github.com/lukiasz/Zippable
另外,如果您覺得這很有趣,我強烈推薦Jon Skeet 的 Reimplementing LINQ to Objects 文章。
玩得開心!
您可以將 C# 中的許多列表與級聯 zip 方法、匿名類和元組結果組合在一起。
List<string> list1 = new List<string> { "test", "otherTest" };
List<string> list2 = new List<string> { "item", "otherItem" };
List<string> list3 = new List<string> { "value", "otherValue" };
IEnumerable<Tuple<string, string, string>> result = list1
.Zip(list2, (e1, e2) => new {e1, e2})
.Zip(list3, (z1, e3) => Tuple.Create(z1.e1, z1.e2, e3));
結果是:
[0]
{(test, item, value)}
Item1: "test"
Item2: "item"
Item3: "value"
class Program
{
static void Main(string[] args)
{
List<string> list1 = new List<string> { "test", "otherTest" };
List<string> list2 = new List<string> { "item", "otherItem" };
List<string> list3 = new List<string> { "value", "otherValue" };
var result = CombineListsByLayers(list1, list2, list3);
}
public static List<string>[] CombineListsByLayers(params List<string>[] sourceLists)
{
var results = new List<string>[sourceLists[0].Count];
for (var i = 0; i < results.Length; i++)
{
results[i] = new List<string>();
foreach (var sourceList in sourceLists)
results[i].Add(sourceList[i]);
}
return results;
}
您可以將這些List<string>
組合成List<List<string>>
並聚合它
List<string> list1 = new List<string> { "test", "otherTest" };
List<string> list2 = new List<string> { "item", "otherItem" };
List<string> list3 = new List<string> { "value", "otherValue" };
var list = new List<List<string>>() { list1, list2, list3 }
.Aggregate(
Enumerable.Range(0, list1.Count).Select(e => new List<string>()),
(prev, next) => prev.Zip(next, (first, second) => { first.Add(second); return first; })
)
.Select(e => new
{
a = e.ElementAt(0),
b = e.ElementAt(1),
c = e.ElementAt(2)
});
結果
[
{
"a": "test",
"b": "item",
"c": "value"
},
{
"a": "otherTest",
"b": "otherItem",
"c": "otherValue"
}
]
用於壓縮任意數量的不同大小列表的通用解決方案:
public static IEnumerable<TItem> ZipAll<TItem>(this IReadOnlyCollection<IEnumerable<TItem>> enumerables)
{
var enumerators = enumerables.Select(enumerable => enumerable.GetEnumerator()).ToList();
bool anyHit;
do
{
anyHit = false;
foreach (var enumerator in enumerators.Where(enumerator => enumerator.MoveNext()))
{
anyHit = true;
yield return enumerator.Current;
}
} while (anyHit);
foreach (var enumerator in enumerators)
{
enumerator.Dispose();
}
}
.. 及以后Zip
可用於生成具有來自三個指定序列的元素的元組序列。 [文檔]
var titles = new string[] { "Analyst", "Consultant", "Supervisor"};
var names = new string[] { "Adam", "Eve", "Michelle" };
var surnames = new string[] { "First", "Second", "Third" };
IEnumerable<(string Title, string Name, string Surname)> zip = titles.Zip(names, surnames);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.