C# 一次循环遍历 2 个列表
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/242417/
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
Looping through 2 Lists at once
提问by Graviton
I have two lists that are of the same length, is it possible to loop through these two lists at once?
我有两个长度相同的列表,是否可以一次遍历这两个列表?
I am looking for the correct syntax to do the below
我正在寻找正确的语法来执行以下操作
foreach itemA, itemB in ListA, ListB
{
Console.WriteLine(itemA.ToString()+","+itemB.ToString());
}
do you think this is possible in C#? And if it is, what is the lambda expression equivalent of this?
你认为这在 C# 中可能吗?如果是,那么与此等效的 lambda 表达式是什么?
采纳答案by Marc Gravell
[edit]: to clarify; this is useful in the generic LINQ / IEnumerable<T>
context, where you can't usean indexer, because a: it doesn't exist on an enumerable, and b: you can't guarantee that you can read the data more than once. Since the OP mentions lambdas, it occurs that LINQ might not be too far away (and yes, I do realise that LINQ and lambdas are not quite the same thing).
[编辑]:澄清;这在不能使用索引器的通用 LINQ /IEnumerable<T>
上下文中很有用,因为 a: 它不存在于可枚举中,而 b: 您不能保证可以多次读取数据。由于 OP 提到了 lambdas,因此 LINQ 可能不会太远(是的,我确实意识到 LINQ 和 lambdas 并不完全相同)。
It sounds like you need the missing Zip
operator; you can spoof it:
听起来您需要缺少的Zip
运算符;你可以欺骗它:
static void Main()
{
int[] left = { 1, 2, 3, 4, 5 };
string[] right = { "abc", "def", "ghi", "jkl", "mno" };
// using KeyValuePair<,> approach
foreach (var item in left.Zip(right))
{
Console.WriteLine("{0}/{1}", item.Key, item.Value);
}
// using projection approach
foreach (string item in left.Zip(right,
(x,y) => string.Format("{0}/{1}", x, y)))
{
Console.WriteLine(item);
}
}
// library code; written once and stuffed away in a util assembly...
// returns each pais as a KeyValuePair<,>
static IEnumerable<KeyValuePair<TLeft,TRight>> Zip<TLeft, TRight>(
this IEnumerable<TLeft> left, IEnumerable<TRight> right)
{
return Zip(left, right, (x, y) => new KeyValuePair<TLeft, TRight>(x, y));
}
// accepts a projection from the caller for each pair
static IEnumerable<TResult> Zip<TLeft, TRight, TResult>(
this IEnumerable<TLeft> left, IEnumerable<TRight> right,
Func<TLeft, TRight, TResult> selector)
{
using(IEnumerator<TLeft> leftE = left.GetEnumerator())
using (IEnumerator<TRight> rightE = right.GetEnumerator())
{
while (leftE.MoveNext() && rightE.MoveNext())
{
yield return selector(leftE.Current, rightE.Current);
}
}
}
回答by jcelgin
It'll be much simpler to just do it in a plain old for loop instead...
在一个普通的旧 for 循环中执行它会简单得多......
for(int i=0; i<ListA.Length; i++)
{
Console.WriteLine(ListA[i].ToString() + ", " + ListB[i].ToString());
}
回答by jcelgin
You can do it explicit.
你可以明确地做到这一点。
IEnumerator ListAEnum = ListA.GetEnumerator();
IEnumerator ListBEnum = ListB.GetEnumerator();
ListBEnum.MoveNext();
while(ListAEnum.MoveNext()==true)
{
itemA=ListAEnum.getCurrent();
itemB=ListBEnum.getCurrent();
Console.WriteLine(itemA.ToString()+","+itemB.ToString());
}
At least this (or something like this) is what the compiler does for a foreach-loop. I haven't tested it though and I guess some template parameters are missing for the enumerators.
至少这个(或类似的东西)是编译器为 foreach 循环所做的。我还没有测试过它,我想枚举器缺少一些模板参数。
Just look up GetEnumerator() from List and the IEnumerator-Interface.
只需从 List 和 IEnumerator-Interface 中查找 GetEnumerator() 即可。
回答by gimel
Senthil Kumar's tech blog, has a series covering implementations of (Python) Itertools for C#, including itertools.izip
.
Senthil Kumar 的技术博客有一系列涵盖C#的(Python) Itertools 实现,包括itertools.izip
.
From Itertools for C# - Cycle and Zip, you have a solution for any number of iterables(not only List<T>). Note that Zip
yields an Array
on each iteration:
从Itertools for C# - Cycle 和 Zip,您可以为任意数量的可迭代对象(不仅是List<T>)提供解决方案。请注意,每次迭代都会Zip
产生一个Array
:
public static IEnumerable<T[]> Zip<T>(params IEnumerable<T>[] iterables)
{
IEnumerator<T>[] enumerators = Array.ConvertAll(iterables, (iterable) => iterable.GetEnumerator());
while (true)
{
int index = 0;
T[] values = new T[enumerators.Length];
foreach (IEnumerator<T> enumerator in enumerators)
{
if (!enumerator.MoveNext())
yield break;
values[index++] = enumerator.Current;
}
yield return values;
}
}
}
The code gets enumerators for all the iterables, moves all enumerators forward, accumulates their current values into an array and yields the array. It does this until any one of the enumerators runs out of elements.
该代码获取所有可迭代对象的枚举数,将所有枚举数向前移动,将它们的当前值累加到一个数组中并生成该数组。它会这样做,直到任何一个枚举器用完元素。
回答by PiRX
I recommend using plain old for loop, but you should consider different array lengths. So
我建议使用普通的 for 循环,但您应该考虑不同的数组长度。所以
for(int i=0; i<ListA.Length; i++)
{
Console.WriteLine(ListA[i].ToString() + ", " + ListB[i].ToString());
}
can turn into
可以变成
for(int i = 0; i < Math.Min(ListA.Length, ListB.Lenght); i++)
{
Console.WriteLine(ListA[i].ToString() + ", " + ListB[i].ToString());
}
or even into
甚至进入
for(int i = 0; i < Math.Max(ListA.Length, ListB.Lenght); i++)
{
string valueA = i < ListA.Length ? listA[i].ToString() : "";
string valueB = i < ListB.Length ? listB[i].ToString() : "";
Console.WriteLine(valueA+ ", " + valueB);
}
回答by sonjz
I had this same problem but using lists of objects with lists inside of them.. for what its worth, this might help someone with the same issue.
我遇到了同样的问题,但是使用其中包含列表的对象列表......不管它的价值,这可能会帮助遇到相同问题的人。
The running time of this isn't very good since IndexOf is O(n), but at the time, I'm dealing with a lot more inner-foreach loops than in this example, so I didn't want to deal with handling iterator variables.
运行时间不是很好,因为 IndexOf 是 O(n),但当时,我处理的内部 foreach 循环比这个例子中的多得多,所以我不想处理迭代器变量。
At times like this I very much miss PHPs foreach($arrayList as $key => $value) notation... maybe I'm missing something in C#, there's got to be a way to get the index in O(c) time! (sadly this post says no: Getting the array key in a 'foreach' loop)
在这样的时候,我非常想念 PHP 的 foreach($arrayList as $key => $value) 符号......也许我在 C# 中遗漏了一些东西,必须有一种方法可以在 O(c) 时间内获取索引!(遗憾的是,这篇文章说不:在“foreach”循环中获取数组键)
class Stock {
string symbol;
List<decimal> hourlyPrice; // provides a list of 24 decimals
}
// get hourly prices from yesterday and today
List<Stock> stockMondays = Stocks.GetStock("GOOGL,IBM,AAPL", DateTime.Now.AddDay(-1));
List<Stock> stockTuesdays = Stocks.GetStock("GOOGL,IBM,AAPL", DateTime.Now);
try {
foreach(Stock sMonday in stockMondays) {
Stock sTuesday = stockTuesday[stockMondays.IndexOf(sMonday)];
foreach(decimal mondayPrice in sMonday.prices) {
decimal tuesdayPrice = sTuesday.prices[sMonday.prices.IndexOf(mondayPrice)];
// do something now
}
}
} catch (Exception ex) { // some reason why list counts aren't matching? }
回答by Joy Fernandes
I have this small function which helps me to iterate through this two list objects. schema is of type SqlData, which is a class that hold three properties. And data is a list that holds values of dynamic type. First I'm iterating through the schema collection and than using the index of item to iterate through the data object.
我有这个小函数可以帮助我遍历这两个列表对象。schema 是 SqlData 类型,它是一个包含三个属性的类。而 data 是一个包含动态类型值的列表。首先,我遍历模式集合,然后使用 item 的索引来遍历数据对象。
public List<SqlData> SqlDataBinding(List<SqlData> schema, List<dynamic> data)
{
foreach (SqlData item in schema)
{
item.Values = data[schema.IndexOf(item)];
}
return schema
}