我知道这个问题之前已被问过多次,但我尝试了答案,但它们似乎没有用.
我有两个长度相同但类型不同的列表,我想在list1[i]连接的同时迭代它们list2[i].
例如:
假设我有list1(as List<string>)和list2(as List<int>)
我想做点什么
foreach( var listitem1, listitem2 in list1, list2)
{
// do stuff
}
Run Code Online (Sandbox Code Playgroud)
这可能吗?
sll*_*sll 44
这可以使用.NET 4 LINQ Zip()运算符或使用开源的MoreLINQ库来提供Zip()运算符,因此您可以在更早期的.NET版本中使用它
来自MSDN的示例:
int[] numbers = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three" };
// The following example concatenates corresponding elements of the
// two input sequences.
var numbersAndWords = numbers.Zip(words, (first, second) => first + " " + second);
foreach (var item in numbersAndWords)
{
Console.WriteLine(item);
}
// OUTPUT:
// 1 one
// 2 two
// 3 three
Run Code Online (Sandbox Code Playgroud)
有用的链接:
Stu*_*tLC 31
编辑 - 在两个集合中的同一索引处进行迭代
如果要求是以"同步"方式移动两个集合,即将第一个集合的第一个元素与第二个集合的第一个元素一起使用,那么将第二个元素与第二个集合一起使用,依此类推,而不需要执行任何一方影响代码,然后查看@sll的答案并用于.Zip()在同一索引处投射出元素对,直到其中一个集合用完了元素.
更普遍
foreach您可以使用该方法IEnumerator从IEnumerable两个集合中访问,而不是使用该GetEnumerator()方法,然后MoveNext()在需要转移到该集合中的下一个元素时调用集合.当处理两个或更多个有序流时,这种技术很常见,而不需要实现流.
var stream1Enumerator = stream1.GetEnumerator();
var stream2Enumerator = stream2.GetEnumerator();
var currentGroupId = -1; // Initial value
// i.e. Until stream1Enumerator runs out of
while (stream1Enumerator.MoveNext())
{
// Now you can iterate the collections independently
if (stream1Enumerator.Current.Id != currentGroupId)
{
stream2Enumerator.MoveNext();
currentGroupId = stream2Enumerator.Current.Id;
}
// Do something with stream1Enumerator.Current and stream2Enumerator.Current
}
Run Code Online (Sandbox Code Playgroud)
正如其他人所指出的那样,如果集合具体化并支持索引(例如ICollection接口),您也可以使用下标[]运算符,尽管现在感觉相当笨拙:
var smallestUpperBound = Math.Min(collection1.Count, collection2.Count);
for (var index = 0; index < smallestUpperBound; index++)
{
// Do something with collection1[index] and collection2[index]
}
Run Code Online (Sandbox Code Playgroud)
最后,还有一个Linq的重载,.Select()它提供了返回元素的索引序号,这也很有用.
例如,下面将所有元素collection1与前两个元素配对collection2:
var alternatePairs = collection1.Select(
(item1, index1) => new
{
Item1 = item1,
Item2 = collection2[index1 % 2]
});
Run Code Online (Sandbox Code Playgroud)
Ode*_*ded 16
简短的回答是不,你不能.
更长的答案是因为foreach是语法糖 - 它从集合中获取迭代器并调用Next它.这两个集合不可能同时进行.
如果您只想拥有一个循环,则可以使用for循环并对两个集合使用相同的索引值.
for(int i = 0; i < collectionsLength; i++)
{
list1[i];
list2[i];
}
Run Code Online (Sandbox Code Playgroud)
另一种方法是使用LINQ Zip运算符(.NET 4.0的新增功能)将两个集合合并为一个集合并迭代结果.
foreach(var tup in list1.Zip(list2, (i1, i2) => Tuple.Create(i1, i2)))
{
var listItem1 = tup.Item1;
var listItem2 = tup.Item2;
/* The "do stuff" from your question goes here */
}
Run Code Online (Sandbox Code Playgroud)
虽然可以这样你的"做东西"可以放在lambda中,这里创建一个元组,这会更好.
如果集合是可以迭代的,那么for()循环可能更简单.
更新:现在有了ValueTupleC#7.0 的内置支持,我们可以使用:
foreach ((var listitem1, var listitem2) in list1.Zip(list2, (i1, i2) => (i1, i2)))
{
/* The "do stuff" from your question goes here */
}
Run Code Online (Sandbox Code Playgroud)