C# 使用foreach循环两个以上的列表

C# 使用foreach循环两个以上的列表,c#,C#,我试图通过合并它们来循环五个列表 我知道这很好用 var zipped = letters.Zip(numbers, Tuple.Create); foreach (var tuple in zipped) { Console.WriteLine(tuple.Item1); Console.WriteLine(tuple.Item2); } 但我想知道我是否可以使用同样的方法,但包括更多的列表 让我们假设我有列表号码、字母、单词、图片和歌曲 那么这个循环会是什么样子

我试图通过合并它们来循环五个列表

我知道这很好用

var zipped = letters.Zip(numbers, Tuple.Create);

 foreach (var tuple in zipped)
 {
     Console.WriteLine(tuple.Item1);
     Console.WriteLine(tuple.Item2);
 }
但我想知道我是否可以使用同样的方法,但包括更多的列表

让我们假设我有列表号码、字母、单词、图片和歌曲


那么这个循环会是什么样子呢?

最简单的方法可能是多次重新实现Zip

public static IEnumerable<Tuple<T1, T2>> ZipTuple<T1, T2>(
    this IEnumerable<T1> source1,
    IEnumerable<T2> source2)

public static IEnumerable<Tuple<T1, T2, T3>> ZipTuple<T1, T2, T3>(
    this IEnumerable<T1> source1,
    IEnumerable<T2> source2,
    IEnumerable<T3> source3)

public static IEnumerable<Tuple<T1, T2, T3, T4>> ZipTuple<T1, T2, T3, T4>(
    this IEnumerable<T1> source1,
    IEnumerable<T2> source2,
    IEnumerable<T3> source3,
    IEnumerable<T3> source4)
我可能会从头开始独立地实现每一个,但您可以通过对前一个ZipTuple的一个调用和对每种情况下的Zip的一个调用来实现,例如

public static IEnumerable<Tuple<T1, T2, T3>> ZipTuple<T1, T2, T3>(
    this IEnumerable<T1> source1,
    IEnumerable<T2> source2,
    IEnumerable<T3> source3)
{
    return source1
        .ZipTuple(source2)
        .Zip(source3, (t1, extra) => Tuple.Create(t1.Item1, t1.Item2, extra));
}

public static IEnumerable<Tuple<T1, T2, T3, T4>> ZipTuple<T1, T2, T3, T4>(
    this IEnumerable<T1> source1,
    IEnumerable<T2> source2,
    IEnumerable<T3> source3,
    IEnumerable<T4> source4)
{
    return source1
        .ZipTuple(source2, source3)
        .Zip(source4, (t1, extra) => Tuple.Create(t1.Item1, t1.Item2, t1.Item3, extra));
}
直接版本将如下所示:

public static IEnumerable<Tuple<T1, T2, T3, T4>> ZipTuple<T1, T2, T3, T4>(
    this IEnumerable<T1> source1,
    IEnumerable<T2> source2,
    IEnumerable<T3> source3,
    IEnumerable<T4> source4)
{
    // TODO: Extract a separate public method from the implementation
    // method and perform eager validation for nullity
    using (var iterator1 = source1.GetEnumerator())
    using (var iterator2 = source2.GetEnumerator())
    using (var iterator3 = source3.GetEnumerator())
    using (var iterator4 = source4.GetEnumerator())
    {
        while (iterator1.MoveNext() && iterator2.MoveNext() &&
               iterator3.MoveNext() && iterator4.MoveNext())
        {
            yield return Tuple.Create(
                iterator1.Current,
                iterator2.Current,
                iterator3.Current,
                iterator4.Current);
        }
    }
}

最简单的方法可能是多次重新实现Zip,例如

public static IEnumerable<Tuple<T1, T2>> ZipTuple<T1, T2>(
    this IEnumerable<T1> source1,
    IEnumerable<T2> source2)

public static IEnumerable<Tuple<T1, T2, T3>> ZipTuple<T1, T2, T3>(
    this IEnumerable<T1> source1,
    IEnumerable<T2> source2,
    IEnumerable<T3> source3)

public static IEnumerable<Tuple<T1, T2, T3, T4>> ZipTuple<T1, T2, T3, T4>(
    this IEnumerable<T1> source1,
    IEnumerable<T2> source2,
    IEnumerable<T3> source3,
    IEnumerable<T3> source4)
我可能会从头开始独立地实现每一个,但您可以通过对前一个ZipTuple的一个调用和对每种情况下的Zip的一个调用来实现,例如

public static IEnumerable<Tuple<T1, T2, T3>> ZipTuple<T1, T2, T3>(
    this IEnumerable<T1> source1,
    IEnumerable<T2> source2,
    IEnumerable<T3> source3)
{
    return source1
        .ZipTuple(source2)
        .Zip(source3, (t1, extra) => Tuple.Create(t1.Item1, t1.Item2, extra));
}

public static IEnumerable<Tuple<T1, T2, T3, T4>> ZipTuple<T1, T2, T3, T4>(
    this IEnumerable<T1> source1,
    IEnumerable<T2> source2,
    IEnumerable<T3> source3,
    IEnumerable<T4> source4)
{
    return source1
        .ZipTuple(source2, source3)
        .Zip(source4, (t1, extra) => Tuple.Create(t1.Item1, t1.Item2, t1.Item3, extra));
}
直接版本将如下所示:

public static IEnumerable<Tuple<T1, T2, T3, T4>> ZipTuple<T1, T2, T3, T4>(
    this IEnumerable<T1> source1,
    IEnumerable<T2> source2,
    IEnumerable<T3> source3,
    IEnumerable<T4> source4)
{
    // TODO: Extract a separate public method from the implementation
    // method and perform eager validation for nullity
    using (var iterator1 = source1.GetEnumerator())
    using (var iterator2 = source2.GetEnumerator())
    using (var iterator3 = source3.GetEnumerator())
    using (var iterator4 = source4.GetEnumerator())
    {
        while (iterator1.MoveNext() && iterator2.MoveNext() &&
               iterator3.MoveNext() && iterator4.MoveNext())
        {
            yield return Tuple.Create(
                iterator1.Current,
                iterator2.Current,
                iterator3.Current,
                iterator4.Current);
        }
    }
}

也许我很愚蠢,但是如果所有列表的长度都相同,for循环通常会很好:

for (int i = 0; i < numbers.Count; i++)
{
    var n = numbers[i];
    var l = letters[i];
    var w = words[i];
    var p = pictures[i];
    var s = songs[i];

    // use your variables

    Console.WriteLine($"number  = {n}");
    Console.WriteLine($"letter  = {l}");
    Console.WriteLine($"word    = {w}");
    Console.WriteLine($"picture = {p}");
    Console.WriteLine($"song    = {s}");
}

也许我很愚蠢,但是如果所有列表的长度都相同,for循环通常会很好:

for (int i = 0; i < numbers.Count; i++)
{
    var n = numbers[i];
    var l = letters[i];
    var w = words[i];
    var p = pictures[i];
    var s = songs[i];

    // use your variables

    Console.WriteLine($"number  = {n}");
    Console.WriteLine($"letter  = {l}");
    Console.WriteLine($"word    = {w}");
    Console.WriteLine($"picture = {p}");
    Console.WriteLine($"song    = {s}");
}

不幸的是,在C语言中,您不能定义一个具有您想要的通用参数的通用方法。因此,您必须为任意数量的泛型类型定义Zip函数

例如,对于3个通用参数:

public static IEnumerable<T> Zip<T1,T2,T3> (this IEnumerable<T1> e1, IEnumerable<T2> e2, IEnumerable<T3> e3) 
{
    var i1 = e1.GetEnumerator();
    var i2 = e2.GetEnumerator();
    var i3 = e3.GetEnumerator();

    // warning: this implementation does not fail if the enumerable do not
    // have the same sizes, it stops when the shortest one is enumerated
    while (i1.MoveNext() && i2.MoveNext() && i3.MoveNext()) {
        yield return Tuple.Create(i1.Current,i2.Current,i3.Current);
    }
}

不幸的是,在C语言中,您不能定义一个具有您想要的通用参数的通用方法。因此,您必须为任意数量的泛型类型定义Zip函数

例如,对于3个通用参数:

public static IEnumerable<T> Zip<T1,T2,T3> (this IEnumerable<T1> e1, IEnumerable<T2> e2, IEnumerable<T3> e3) 
{
    var i1 = e1.GetEnumerator();
    var i2 = e2.GetEnumerator();
    var i3 = e3.GetEnumerator();

    // warning: this implementation does not fail if the enumerable do not
    // have the same sizes, it stops when the shortest one is enumerated
    while (i1.MoveNext() && i2.MoveNext() && i3.MoveNext()) {
        yield return Tuple.Create(i1.Current,i2.Current,i3.Current);
    }
}

你可以用几种方法来做

public static IEnumerable<T> Zip<T>(this List<T> source, params IEnumerable<T>[] collections)
    {
        source.AddRange(collections.SelectMany(collection => collection));
        return source;
    }
或:

或者,如果需要元组,可以执行以下操作:

letters.Zip(numbers, Tuple.Create).Zip(pictures, (x, y) => Tuple.Create(x.Item1, x.Item2, y)).Zip(songs, Tuple.Create)


你可以用几种方法来做

public static IEnumerable<T> Zip<T>(this List<T> source, params IEnumerable<T>[] collections)
    {
        source.AddRange(collections.SelectMany(collection => collection));
        return source;
    }
或:

或者,如果需要元组,可以执行以下操作:

letters.Zip(numbers, Tuple.Create).Zip(pictures, (x, y) => Tuple.Create(x.Item1, x.Item2, y)).Zip(songs, Tuple.Create)



for循环有什么问题?有一个函数可以转储列表,并向其发送一个包含所有所需列表的组合列表,但您当然需要在每个列表中都有相似的成员。您通常可以使用AddRange方法。您可以用linq Select方法替换foreach循环。请不要提出全新的问题。如果您还有其他问题,请提出新问题,而不是编辑现有问题。你的问题变成了一个移动的目标。@Patrickhoffman这与添加示例的问题完全相同。。。为什么要删除它???for循环有什么问题?有一个函数可以转储列表并向其发送一个包含所有所需列表的组合列表,但您当然需要在每个列表中都有相似的成员。您通常可以使用AddRange方法。您可以用linq Select方法替换foreach循环。请不要提出全新的问题。如果您还有其他问题,请提出新问题,而不是编辑现有问题。你的问题变成了一个移动的目标。@Patrickhoffman这与添加示例的问题完全相同。。。你为什么要删除它???是的,你可以按照你展示的方式实现ZipTuple,但可能会给孩子们带来不好的想法。另外,带有for循环的实现非常简单,如果不展示yield语法有多好,那就很遗憾了。@d-b:将添加一个例子。啊,很好,我想我会这样做,因此我的答案如下。您能详细介绍一下使用块的需要吗?我的意思是,为什么IEnumerator实现IDisposable?这是因为一些COM遗留问题吗?@John.P:正如Patrick所说,你在更新中要求的正是我提供的——你只需要拥有与你需要的类型参数一样多的重载。是的,你可以按照你展示的方式实现ZipTuple,但可能会给孩子们一些坏主意。另外,带有for循环的实现非常简单,如果不展示yield语法有多好,那就很遗憾了。@d-b:将添加一个例子。啊,很好,我想我会这样做,因此我的答案如下。您能详细介绍一下使用块的需要吗?我的意思是,为什么IEnumerator实现IDisposable?这是因为某些COM遗留问题吗?@John.P:正如Patrick所说,您在更新中要求的正是我所提供的-您只需要拥有与您需要的类型参数一样多的重载。这通常不适用于IEnumerable,它假设输入是ListIt,您可以使用Count和ElementAt作为替换@d-B哦,不,这会使IEnumerable方法重复太多次。每个ElementAt都包含自己的for循环!它将检查源是否是一个列表并使用它。自己遍历IEnumerable也是可能的。@d-b当然在IEnumerable上使用Count和ElementAt是相当愚蠢的,但作者询问的是list,这是遍历多个列表的最佳方式。这通常对IEnumerable不起作用,它假设输入是ListIt,您可以使用Count和ElementAt作为替换@d-B哦,不,这会使IEnumerable方法重复太多次。每个ElementAt都包含自己的for循环!它将检查源是否是一个列表并使用它。步行
IEnumerable本身也是可能的。@d-b当然在IEnumerable上使用Count和ElementAt是相当愚蠢的,但作者询问的是列表,这是迭代多个列表的最佳方式。请查看我更新的问题。有可能合并我包含的所有列表吗?@John.P:如果你想循环浏览大量列表,Patrick描述的for循环确实是一种方法。请查看我更新的问题。有可能合并我包含的所有列表吗?@John.P:如果你想在大量列表中循环,Patrick描述的for循环确实是一种方法。