简体   繁体   English

使用foreach同时遍历多个列表(语法糖)

[英]using foreach to iterate simultaneously through multiple lists (syntax sugar)

Hi is there a way to do things like this: 嗨,有一种方法可以执行以下操作:

for (int i = 0; i < Math.Min(a.Count, b.Count); i++)
{
    // Do stuff
    //a[i]
    //b[i]
}

with Foreach? 与Foreach?

because it would be nice to write something like 因为写这样的东西会很好

foreach(var item1 in list1 and var item2 in list2 /* ....*/)
{
   item1.use(item2);
}

EDIT 编辑

ok sorry i wasn't clear enough for some people so here am hopefully better explanation 好的,抱歉,我对某些人还不够清楚,因此希望这里有更好的解释

List<classA> listA = fillListA();
List<classB> listB = fillListB();
//here could be infinity many lists of sometimes diffrent T types

Now i want to perform some sort of ForEach because i dont like to do it with a for loop it should be simple and clear well something like 现在我想执行某种形式的ForEach,因为我不喜欢使用for循环来完成它,它应该简单明了,就像

foreach(var item1 in list1 and var item2 in list2 /* and ...*/)
{
    item1.use(item2);
}

AFAIK i cant modifie such a keay word class thing so i thought ok build the iterator like Parallel.ForEach did ForEach<TSource>(IEnumerable<TSource>, Action<TSource>) but her i get stucked because i don't know how implement it 据我所知,我不能modifie这样的凯伊字类的东西,所以我想确定建立一个像迭代器Parallel.ForEachForEach<TSource>(IEnumerable<TSource>, Action<TSource>)但她我得到stucked,因为我不知道如何实现它

Static.ForEach<TSource>(IEnumerable<TSource>,IEnumerable<TSource>, ???Action<TSource,???>????)

You can do what foreach does under the hood, but with two enumerators: 您可以执行foreach的幕后工作,但是有两个枚举器:

using(var e1 = list1.GetEnumerator())
using(var e2 = list2.GetEnumerator())
{
    while(e1.MoveNext() && e2.MoveNext())
    {
         var item1 = e1.Current;
         var item2 = e2.Current;

         // use item1 and item2
    }
}

For convenience, you can write an extension method like the following that takes an action: 为了方便起见,您可以编写如下所示的扩展方法来执行操作:

public static void ZipDo<T1, T2>( this IEnumerable<T1> first, IEnumerable<T2> second, Action<T1, T2> action)
{
    using (var e1 = first.GetEnumerator())
    using (var e2 = second.GetEnumerator())
    {
        while (e1.MoveNext() && e2.MoveNext())
        {
            action(e1.Current, e2.Current);
        }
    }
}

and use it like: 并像这样使用它:

list1.ZipDo(list2, (i1,i2) => i1.Use(i2));

By the way, you can expand this to use 3 or more lists: 顺便说一句,您可以将其扩展为使用3个或更多列表:

public static void ZipDo<T1, T2, T3>(this IEnumerable<T1> first,
    IEnumerable<T2> second, IEnumerable<T3> third,
    Action<T1, T2, T3> action)
{
    using (var e1 = first.GetEnumerator())
    using (var e2 = second.GetEnumerator())
    using (var e3 = third.GetEnumerator())
    {
        while (e1.MoveNext() && e2.MoveNext() && e3.MoveNext())
        {
            action(e1.Current, e2.Current, e3.Current);
        }
    }
}

The approach above is required when the collections have different generic types. 当集合具有不同的泛型类型时,需要上述方法。 However, if they all have the same generic type, then you can write a flexible method that takes any number of IEnumerable<T> s: 但是,如果它们都具有相同的泛型类型,则可以编写一个灵活的方法,该方法采用任意数量的IEnumerable<T>

public static void ZipAll<T>(this IEnumerable<IEnumerable<T>> all, Action<IEnumerable<T>> action)
{
    var enumerators = all.Select(e => e.GetEnumerator()).ToList();
    try
    {
        while (enumerators.All(e => e.MoveNext()))
            action(enumerators.Select(e => e.Current));
    }
    finally
    {
        foreach (var e in enumerators) 
            e.Dispose();
    }
}

and use it: 并使用它:

var lists = new[] {
     new[]{ 1, 1, 1 }, 
     new[]{ 2, 2, 2 }, 
     new[]{ 3, 3, 3 }};

lists.ZipAll(nums => Console.WriteLine(nums.Sum()));
// 6
// 6
// 6

The only thing I can think of that comes close is Enumerable.Zip along with tuples : 我唯一能想到的就是Enumerable.Zip元组

foreach(var tuple in list1.Zip(list2, Tuple.Create))
{
    tuple.Item1.use(tuple.Item2);
}

Of course, if instead of use , we had a non side-effecting method that produced a third value from the two elements, you could do: 当然,如果不是use ,而是use非副作用方法,该方法从两个元素中产生了第三个值,则可以执行以下操作:

var result = list1.Zip(list2, (item1, item2) => item1.ProduceObject(item2))
                  .ToList(); // if required

you can use Zip method (though only available in .net 4 and above) something like this? 您可以使用Zip方法(尽管仅在.net 4及更高版本中可用)是这样的吗?

List<int> l4 = new List<int> { 1, 2, 3, 4 };
List<int> l5 = new List<int> { 5, 6, 7 };

var l4Andl5 = l4.Zip(l5, (l, m) => new { List1 = l, List2 = m });
foreach (var x in l4Andl5)
{


}

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)
{
    itemA.use(listB[i++]);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM