在C#中使用一个ForEach语句迭代两个列表或数组

Hug*_*ugo 136 c#

这只是为了一般知识:

如果我有两个,让我们说,List,我想用相同的foreach循环迭代,我们能做到吗?

编辑

只是为了澄清,我想这样做:

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];
Run Code Online (Sandbox Code Playgroud)

但是有一个foreach =)

Mar*_*ann 249

这称为Zip操作,将在.NET 4中受支持.

有了这个,你就可以写下这样的东西:

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);
}
Run Code Online (Sandbox Code Playgroud)

作为具有命名字段的匿名类型的替代方法,您还可以使用Tuple及其静态Tuple.Create帮助程序来保存大括号:

foreach (var nw in numbers.Zip(words, Tuple.Create)) 
{
    Console.WriteLine(nw.Item1 + nw.Item2);
}
Run Code Online (Sandbox Code Playgroud)

  • @Hugo:这是函数式编程中的标准构造:) (4认同)
  • 这是一篇关于它的文章:http://community.bartdesmet.net/blogs/bart/archive/2008/11/03/c-4-0-feature-focus-part-3-intermezzo-linq-s-new-拉链operator.aspx (2认同)
  • 对于这些Zip操作一无所知,我将对该主题进行小型研究。谢谢! (2认同)
  • 从C#7开始,您还可以使用ValueTuple(请参阅/sf/answers/3193242391/)代替匿名类型或Tuple.Create。即`foreach((var number,var word)in numbers.Zip(words,(n,w)=&gt;(n,w))){...}`。 (2认同)

Mat*_*rný 22

从 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}");
}
Run Code Online (Sandbox Code Playgroud)

编辑 2022-04-14

自原始答案(和 .NET Core 3.0)以来,Zip 扩展方法变得更好,因此您现在可以编写

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}");
}
Run Code Online (Sandbox Code Playgroud)

从 .NET 6 开始还支持三个数组的变体

int[] nums = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three", "four" };

foreach (var (x, y) in nums.Zip(words))
{
    Console.WriteLine($"{x}: {y}");
}
Run Code Online (Sandbox Code Playgroud)

  • @JohnAugust 它在遍历较短的序列后终止。来自文档:“如果序列不具有相同数量的元素,则该方法会合并序列,直到到达其中一个序列的末尾。例如,如果一个序列包含三个元素,另一个序列包含四个元素,则结果序列将只有三个元素。” (3认同)

Joe*_*Joe 13

如果您不想等待.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());
    }
}
Run Code Online (Sandbox Code Playgroud)


alb*_*ein 12

您可以使用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
}
Run Code Online (Sandbox Code Playgroud)