如何在 C# Zip 中组合两个以上的通用列表?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10297124/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to combine more than two generic lists in C# Zip?
提问by Snake Eyes
I have three (it's possible to have more than 3-4 generic list, but in this example let 3) generic lists.
我有三个(可能有超过 3-4 个通用列表,但在本例中让 3 个)通用列表。
List<string> list1
List<string> list2
List<string> list3
all lists have same number of elements (same counts).
所有列表都具有相同数量的元素(相同的计数)。
I used that for combining two lists with ZIP :
我用它来将两个列表与 ZIP 结合起来:
var result = list1.Zip(list2, (a, b) => new {
test1 = f,
test2 = b
}
I used that for foreachstatement, to avoid foreacheach List, like
我用它来foreach声明,以避免foreach每个列表,比如
foreach(var item in result){
Console.WriteLine(item.test1 + " " + item.test2);
}
How to use simmilary with Zip for three lists ?
如何将 simmilary 与 Zip 用于三个列表?
Thanks
谢谢
EDIT:
编辑:
I want like:
我想要:
List<string> list1 = new List<string>{"test", "otherTest"};
List<string> list2 = new List<string>{"item", "otherItem"};
List<string> list3 = new List<string>{"value", "otherValue"};
after ZIP (I don't know method), I want to result (in VS2010 debug mode)
ZIP后(我不知道方法),我想要结果(在VS2010调试模式下)
[0] { a = {"test"},
b = {"item"},
c = {"value"}
}
[1] { a = {"otherTest"},
b = {"otherItem"},
c = {"otherValue"}
}
How to do that ?
怎么做 ?
采纳答案by Cristian Lupascu
The most obvious way for me would be to use Ziptwice.
对我来说最明显的方法是使用Zip两次。
For example,
例如,
var results = l1.Zip(l2, (x, y) => x + y).Zip(l3, (x, y) => x + y);
would combine (add) the elements of three List<int>objects.
将组合(添加)三个List<int>对象的元素。
Update:
更新:
You could define a new extension method that acts like a Zipwith three IEnumerables, like so:
您可以定义一个新的扩展方法,它的作用类似于Zip带有三个IEnumerables 的 a,如下所示:
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);
}
}
}
The usage (in the same context as above) now becomes:
用法(在与上述相同的上下文中)现在变为:
var results = l1.ZipThree(l2, l3, (x, y, z) => x + y + z);
Similarly, you three lists can now be combined with:
同样,您现在可以将三个列表与:
var results = list1.ZipThree(list2, list3, (a, b, c) => new { a, b, c });
回答by G.Y
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;
}
回答by andrew.fox
You can combine many lists in C# with cascade zip methods and anonymous classes and Tuple result.
您可以将 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));
The result is:
结果是:
[0]
{(test, item, value)}
Item1: "test"
Item2: "item"
Item3: "value"
回答by lukiasz
There is another quite interesting solution that I'm aware of. It's interesting mostly from educational perspective but if one needs to perform zipping different counts of lists A LOT, then it also might be useful.
我知道还有另一个非常有趣的解决方案。从教育的角度来看,这很有趣,但如果需要执行压缩不同数量的列表很多,那么它也可能有用。
This method overrides .NET's LINQ SelectManyfunction which is taken by a convention when you use LINQ's query syntax. The standard SelectManyimplementation does a Cartesian Product. The overrided one can do zipping instead. The actual implementation could be:
此方法会覆盖 .NET 的 LINQSelectMany函数,当您使用 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;
}
It looks a bit scary but it is a logic of zipping which if written once, can be used in many places and the client's code look pretty nice - you can zip any number of IEnumerable<T>using standard LINQ query syntax:
它看起来有点吓人,但它是一种压缩逻辑,如果编写一次,可以在许多地方使用,并且客户端的代码看起来很不错 - 您可以IEnumerable<T>使用标准 LINQ 查询语法压缩任意数量:
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 }";
If you then execute:
如果然后执行:
foreach (var result in results)
Console.WriteLine(result);
You will get:
你会得到:
Analyst Adam First
Consultant Eve Second
Supervisor Michelle Third
You should keep this extension private within your class because otherwise you will radically change behavior of surrounding code. Also, a new type will be useful so that it won't colide with standard LINQ behavior for IEnumerables.
你应该在你的类中保持这个扩展是私有的,否则你会从根本上改变周围代码的行为。此外,新类型将非常有用,因此它不会与 IEnumerables 的标准 LINQ 行为发生冲突。
For educational purposes I've created once a small c# project with this extension method + few benefits: https://github.com/lukiasz/Zippable
出于教育目的,我使用此扩展方法创建了一个小型 c# 项目 + 一些好处:https: //github.com/lukiasz/Zippable
Also, if you find this interesting, I strongly recommend Jon Skeet's Reimplementing LINQ to Objects articles.
另外,如果您觉得这很有趣,我强烈推荐Jon Skeet 的 Reimplementing LINQ to Objects 文章。
Have fun!
玩得开心!
回答by kogoia
You can combine these List<string>'s into List<List<string>>and aggregate it
您可以将这些组合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)
});
Result
结果
[
{
"a": "test",
"b": "item",
"c": "value"
},
{
"a": "otherTest",
"b": "otherItem",
"c": "otherValue"
}
]
See on dotnetfiddle.net
回答by Mugen
Generic solution for any number of lists of different sizes to zip:
用于压缩任意数量的不同大小列表的通用解决方案:
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();
}
}

