用 C# 中的一个 ForEach 语句迭代两个列表或数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1955766/
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
Iterate two Lists or Arrays with one ForEach statement in C#
提问by Hugo
This just for general knowledge:
这只是一般知识:
If I have two, let's say, List, and I want to iterate both with the same foreach loop, can we do that?
如果我有两个,比如说List,并且我想用相同的 foreach 循环迭代两个,我们可以这样做吗?
Edit
编辑
Just to clarify, I wanted to do this:
只是为了澄清,我想这样做:
List<String> listA = new List<string> { "string", "string" };
List<String> listB = new List<string> { "string", "string" };
for(int i = 0; i < listA.Count; i++)
listB[i] = listA[i];
But with a foreach =)
但是使用 foreach =)
采纳答案by Mark Seemann
This is known as a Zipoperation and will be supported in .NET 4.
这称为Zip操作,将在 .NET 4 中得到支持。
With that, you would be able to write something like:
有了这个,你就可以写出类似的东西:
var numbers = new [] { 1, 2, 3, 4 };
var words = new [] { "one", "two", "three", "four" };
var numbersAndWords = numbers.Zip(words, (n, w) => new { Number = n, Word = w });
foreach(var nw in numbersAndWords)
{
Console.WriteLine(nw.Number + nw.Word);
}
As an alternative to the anonymous type with the named fields, you can also save on braces by using a Tuple and its static Tuple.Create helper:
作为具有命名字段的匿名类型的替代方案,您还可以通过使用元组及其静态 Tuple.Create 助手来节省大括号:
foreach (var nw in numbers.Zip(words, Tuple.Create))
{
Console.WriteLine(nw.Item1 + nw.Item2);
}
回答by Benjamin Podszun
I understand/hope that the lists have the same length: No, your only bet is going with a plain old standard for loop.
我理解/希望列表具有相同的长度:不,您唯一的赌注是使用普通的旧标准 for 循环。
回答by Maximilian Mayerl
No, you would have to use a for-loop for that.
不,您必须为此使用 for 循环。
for (int i = 0; i < lst1.Count; i++)
{
//lst1[i]...
//lst2[i]...
}
You can't do something like
你不能做这样的事情
foreach (var objCurrent1 int lst1, var objCurrent2 in lst2)
{
//...
}
回答by albertein
You can use Union or Concat, the former removes duplicates, the later doesn't
您可以使用 Union 或 Concat,前者删除重复项,后者不删除
foreach (var item in List1.Union(List1))
{
//TODO: Real code goes here
}
foreach (var item in List1.Concat(List1))
{
//TODO: Real code goes here
}
回答by Samuel Neff
Here's a custom IEnumerable<> extension method that can be used to loop through two lists simultaneously.
这是一个自定义的 IEnumerable<> 扩展方法,可用于同时循环遍历两个列表。
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication1
{
public static class LinqCombinedSort
{
public static void Test()
{
var a = new[] {'a', 'b', 'c', 'd', 'e', 'f'};
var b = new[] {3, 2, 1, 6, 5, 4};
var sorted = from ab in a.Combine(b)
orderby ab.Second
select ab.First;
foreach(char c in sorted)
{
Console.WriteLine(c);
}
}
public static IEnumerable<Pair<TFirst, TSecond>> Combine<TFirst, TSecond>(this IEnumerable<TFirst> s1, IEnumerable<TSecond> s2)
{
using (var e1 = s1.GetEnumerator())
using (var e2 = s2.GetEnumerator())
{
while (e1.MoveNext() && e2.MoveNext())
{
yield return new Pair<TFirst, TSecond>(e1.Current, e2.Current);
}
}
}
}
public class Pair<TFirst, TSecond>
{
private readonly TFirst _first;
private readonly TSecond _second;
private int _hashCode;
public Pair(TFirst first, TSecond second)
{
_first = first;
_second = second;
}
public TFirst First
{
get
{
return _first;
}
}
public TSecond Second
{
get
{
return _second;
}
}
public override int GetHashCode()
{
if (_hashCode == 0)
{
_hashCode = (ReferenceEquals(_first, null) ? 213 : _first.GetHashCode())*37 +
(ReferenceEquals(_second, null) ? 213 : _second.GetHashCode());
}
return _hashCode;
}
public override bool Equals(object obj)
{
var other = obj as Pair<TFirst, TSecond>;
if (other == null)
{
return false;
}
return Equals(_first, other._first) && Equals(_second, other._second);
}
}
}
回答by albertein
If you want one element with the corresponding one you could do
如果你想要一个元素和相应的元素,你可以做
Enumerable.Range(0, List1.Count).All(x => List1[x] == List2[x]);
That will return true if every item is equal to the corresponding one on the second list
如果每个项目都等于第二个列表中的相应项目,则返回 true
If that's almost but not quite what you want it would help if you elaborated more.
如果这几乎但不完全是您想要的,那么如果您详细说明会有所帮助。
回答by Rohan West
This method would work for a list implementation and could be implemented as an extension method.
此方法适用于列表实现,并且可以作为扩展方法实现。
public void TestMethod()
{
var first = new List<int> {1, 2, 3, 4, 5};
var second = new List<string> {"One", "Two", "Three", "Four", "Five"};
foreach(var value in this.Zip(first, second, (x, y) => new {Number = x, Text = y}))
{
Console.WriteLine("{0} - {1}",value.Number, value.Text);
}
}
public IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(List<TFirst> first, List<TSecond> second, Func<TFirst, TSecond, TResult> selector)
{
if (first.Count != second.Count)
throw new Exception();
for(var i = 0; i < first.Count; i++)
{
yield return selector.Invoke(first[i], second[i]);
}
}
回答by Joe
If you don't want to wait for .NET 4.0, you could implement your own Zip
method. The following works with .NET 2.0. You can adjust the implementation depending on how you want to handle the case where the two enumerations (or lists) have different lengths; this one continues to the end of the longer enumeration, returning the default values for missing items from the shorter enumeration.
如果您不想等待 .NET 4.0,您可以实现自己的Zip
方法。以下适用于 .NET 2.0。您可以根据您希望如何处理两个枚举(或列表)具有不同长度的情况来调整实现;这个继续到较长枚举的末尾,返回较短枚举中缺失项的默认值。
static IEnumerable<KeyValuePair<T, U>> Zip<T, U>(IEnumerable<T> first, IEnumerable<U> second)
{
IEnumerator<T> firstEnumerator = first.GetEnumerator();
IEnumerator<U> secondEnumerator = second.GetEnumerator();
while (firstEnumerator.MoveNext())
{
if (secondEnumerator.MoveNext())
{
yield return new KeyValuePair<T, U>(firstEnumerator.Current, secondEnumerator.Current);
}
else
{
yield return new KeyValuePair<T, U>(firstEnumerator.Current, default(U));
}
}
while (secondEnumerator.MoveNext())
{
yield return new KeyValuePair<T, U>(default(T), secondEnumerator.Current);
}
}
static void Test()
{
IList<string> names = new string[] { "one", "two", "three" };
IList<int> ids = new int[] { 1, 2, 3, 4 };
foreach (KeyValuePair<string, int> keyValuePair in ParallelEnumerate(names, ids))
{
Console.WriteLine(keyValuePair.Key ?? "<null>" + " - " + keyValuePair.Value.ToString());
}
}
回答by thalm
You could also simply use a local integer variable if the lists have the same length:
如果列表具有相同的长度,您也可以简单地使用局部整数变量:
List<classA> listA = fillListA();
List<classB> listB = fillListB();
var i = 0;
foreach(var itemA in listA)
{
Console.WriteLine(itemA + listB[i++]);
}
回答by Matěj Pokorny
Since C# 7, you can use Tuples...
从 C# 7 开始,您可以使用元组...
int[] nums = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three", "four" };
foreach (var tuple in nums.Zip(words, (x, y) => (x, y)))
{
Console.WriteLine($"{tuple.Item1}: {tuple.Item2}");
}
// or...
foreach (var tuple in nums.Zip(words, (x, y) => (Num: x, Word: y)))
{
Console.WriteLine($"{tuple.Num}: {tuple.Word}");
}