一次循环2个列表

时间:2022-10-19 13:52:13

I have two lists that are of the same length, is it possible to loop through these two lists at once?

我有两个长度相同的列表,是否可以一次循环这两个列表?

I am looking for the correct syntax to do the below

我正在寻找正确的语法来执行以下操作

foreach itemA, itemB in ListA, ListB
{
  Console.WriteLine(itemA.ToString()+","+itemB.ToString());
}

do you think this is possible in C#? And if it is, what is the lambda expression equivalent of this?

你认为这在C#中有可能吗?如果是的话,lambda表达式与此相当的是什么?

7 个解决方案

#1


25  

[edit]: to clarify; this is useful in the generic LINQ / IEnumerable<T> context, where you can't use an indexer, because a: it doesn't exist on an enumerable, and b: you can't guarantee that you can read the data more than once. Since the OP mentions lambdas, it occurs that LINQ might not be too far away (and yes, I do realise that LINQ and lambdas are not quite the same thing).

[编辑]:澄清;这在通用LINQ / IEnumerable 上下文中非常有用,在这种上下文中你不能使用索引器,因为a:它不存在于可枚举中,而b:你不能保证你可以更多地读取数据不止一次。由于OP提到lambdas,所以LINQ可能不会太远(是的,我确实意识到LINQ和lambdas不是完全相同的事情)。

It sounds like you need the missing Zip operator; you can spoof it:

听起来你需要缺少Zip操作符;你可以欺骗它:

static void Main()
{
    int[] left = { 1, 2, 3, 4, 5 };
    string[] right = { "abc", "def", "ghi", "jkl", "mno" };

    // using KeyValuePair<,> approach
    foreach (var item in left.Zip(right))
    {
        Console.WriteLine("{0}/{1}", item.Key, item.Value);
    }

    // using projection approach
    foreach (string item in left.Zip(right,
        (x,y) => string.Format("{0}/{1}", x, y)))
    {
        Console.WriteLine(item);
    }
}

// library code; written once and stuffed away in a util assembly...

// returns each pais as a KeyValuePair<,>
static IEnumerable<KeyValuePair<TLeft,TRight>> Zip<TLeft, TRight>(
    this IEnumerable<TLeft> left, IEnumerable<TRight> right)
{
    return Zip(left, right, (x, y) => new KeyValuePair<TLeft, TRight>(x, y));
}

// accepts a projection from the caller for each pair
static IEnumerable<TResult> Zip<TLeft, TRight, TResult>(
    this IEnumerable<TLeft> left, IEnumerable<TRight> right,
    Func<TLeft, TRight, TResult> selector)
{
    using(IEnumerator<TLeft> leftE = left.GetEnumerator())
    using (IEnumerator<TRight> rightE = right.GetEnumerator())
    {
        while (leftE.MoveNext() && rightE.MoveNext())
        {
            yield return selector(leftE.Current, rightE.Current);
        }
    }
}

#2


11  

It'll be much simpler to just do it in a plain old for loop instead...

相反,在一个普通的旧循环中做它会简单得多......

for(int i=0; i<ListA.Length; i++)
{
    Console.WriteLine(ListA[i].ToString() + ", " + ListB[i].ToString());
}

#3


5  

You can do it explicit.

你可以明确地做到这一点。

IEnumerator ListAEnum = ListA.GetEnumerator();
IEnumerator ListBEnum = ListB.GetEnumerator();

ListBEnum.MoveNext();
while(ListAEnum.MoveNext()==true)
{
  itemA=ListAEnum.getCurrent();
  itemB=ListBEnum.getCurrent();
  Console.WriteLine(itemA.ToString()+","+itemB.ToString());
}

At least this (or something like this) is what the compiler does for a foreach-loop. I haven't tested it though and I guess some template parameters are missing for the enumerators.

至少这个(或类似的东西)是编译器为foreach循环所做的。我没有测试它,我猜想枚举器缺少一些模板参数。

Just look up GetEnumerator() from List and the IEnumerator-Interface.

只需从List和IEnumerator-Interface中查找GetEnumerator()。

#4


1  

I recommend using plain old for loop, but you should consider different array lengths. So

我建议使用普通的旧for循环,但你应该考虑不同的数组长度。所以

for(int i=0; i<ListA.Length; i++)
{
    Console.WriteLine(ListA[i].ToString() + ", " + ListB[i].ToString());
}

can turn into

可以变成

for(int i = 0; i < Math.Min(ListA.Length, ListB.Lenght); i++)
{
    Console.WriteLine(ListA[i].ToString() + ", " + ListB[i].ToString());
}

or even into

甚至进入

    for(int i = 0; i < Math.Max(ListA.Length, ListB.Lenght); i++)
    {
        string valueA = i < ListA.Length ? listA[i].ToString() : "";
        string valueB = i < ListB.Length ? listB[i].ToString() : "";

        Console.WriteLine(valueA+ ", " + valueB);
    }

#5


1  

I had this same problem but using lists of objects with lists inside of them.. for what its worth, this might help someone with the same issue.

我有同样的问题,但使用列表中包含列表的对象...为了它的价值,这可能会帮助有同样问题的人。

The running time of this isn't very good since IndexOf is O(n), but at the time, I'm dealing with a lot more inner-foreach loops than in this example, so I didn't want to deal with handling iterator variables.

由于IndexOf是O(n),所以运行时间不是很好,但是当时我处理的内部 - foreach循环比这个例子要多得多,所以我不想处理迭代器变量。

At times like this I very much miss PHPs foreach($arrayList as $key => $value) notation... maybe I'm missing something in C#, there's got to be a way to get the index in O(c) time! (sadly this post says no: Getting the array key in a 'foreach' loop)

在这种情况下,我非常想念PHPs foreach($ arrayList为$ key => $ value)表示法...也许我在C#中遗漏了一些东西,必须有一种方法可以在O(c)时间内获得索引! (遗憾的是这篇文章说不:在'foreach'循环中获取数组键)

class Stock {
   string symbol;
   List<decimal> hourlyPrice; // provides a list of 24 decimals
}

// get hourly prices from yesterday and today
List<Stock> stockMondays = Stocks.GetStock("GOOGL,IBM,AAPL", DateTime.Now.AddDay(-1));
List<Stock> stockTuesdays = Stocks.GetStock("GOOGL,IBM,AAPL", DateTime.Now);

try {
    foreach(Stock sMonday in stockMondays) {
        Stock sTuesday = stockTuesday[stockMondays.IndexOf(sMonday)];

        foreach(decimal mondayPrice in sMonday.prices) {
            decimal tuesdayPrice = sTuesday.prices[sMonday.prices.IndexOf(mondayPrice)];
            // do something now
        }

    }
} catch (Exception ex) { // some reason why list counts aren't matching? }

#6


0  

Senthil Kumar's tech blog, has a series covering implementations of (Python) Itertools for C#, including itertools.izip.

Senthil Kumar的科技博客,有一系列文章介绍了C#(Python)Itertools的实现,包括itertools.izip。

From Itertools for C# - Cycle and Zip, you have a solution for any number of iterables (not only List<T>). Note that Zip yields an Array on each iteration:

从Itertools for C# - Cycle和Zip,您可以获得任意数量的迭代(不仅仅是List )的解决方案。请注意,Zip会在每次迭代时生成一个数组:

public static IEnumerable<T[]> Zip<T>(params IEnumerable<T>[] iterables)
{
IEnumerator<T>[] enumerators = Array.ConvertAll(iterables, (iterable) =>   iterable.GetEnumerator());

while (true)
{
   int index = 0;
   T[] values = new T[enumerators.Length];

   foreach (IEnumerator<T> enumerator in enumerators)
   {
       if (!enumerator.MoveNext())
          yield break;

        values[index++] = enumerator.Current;
   }

   yield return values;
}

}

The code gets enumerators for all the iterables, moves all enumerators forward, accumulates their current values into an array and yields the array. It does this until any one of the enumerators runs out of elements.

代码获取所有迭代的枚举器,向前移动所有枚举器,将其当前值累积到数组中并生成数组。它会在任何一个枚举器耗尽元素之前执行此操作。

#7


0  

I have this small function which helps me to iterate through this two list objects. schema is of type SqlData, which is a class that hold three properties. And data is a list that holds values of dynamic type. First I'm iterating through the schema collection and than using the index of item to iterate through the data object.

我有这个小函数,它可以帮助我遍历这两个列表对象。 schema的类型为SqlData,它是一个包含三个属性的类。数据是一个包含动态类型值的列表。首先,我在遍历模式集合,而不是使用item的索引来遍历数据对象。

public List<SqlData> SqlDataBinding(List<SqlData> schema, List<dynamic> data)
{
    foreach (SqlData item in schema)
    {
        item.Values = data[schema.IndexOf(item)];
    }
    return schema
}

#1


25  

[edit]: to clarify; this is useful in the generic LINQ / IEnumerable<T> context, where you can't use an indexer, because a: it doesn't exist on an enumerable, and b: you can't guarantee that you can read the data more than once. Since the OP mentions lambdas, it occurs that LINQ might not be too far away (and yes, I do realise that LINQ and lambdas are not quite the same thing).

[编辑]:澄清;这在通用LINQ / IEnumerable 上下文中非常有用,在这种上下文中你不能使用索引器,因为a:它不存在于可枚举中,而b:你不能保证你可以更多地读取数据不止一次。由于OP提到lambdas,所以LINQ可能不会太远(是的,我确实意识到LINQ和lambdas不是完全相同的事情)。

It sounds like you need the missing Zip operator; you can spoof it:

听起来你需要缺少Zip操作符;你可以欺骗它:

static void Main()
{
    int[] left = { 1, 2, 3, 4, 5 };
    string[] right = { "abc", "def", "ghi", "jkl", "mno" };

    // using KeyValuePair<,> approach
    foreach (var item in left.Zip(right))
    {
        Console.WriteLine("{0}/{1}", item.Key, item.Value);
    }

    // using projection approach
    foreach (string item in left.Zip(right,
        (x,y) => string.Format("{0}/{1}", x, y)))
    {
        Console.WriteLine(item);
    }
}

// library code; written once and stuffed away in a util assembly...

// returns each pais as a KeyValuePair<,>
static IEnumerable<KeyValuePair<TLeft,TRight>> Zip<TLeft, TRight>(
    this IEnumerable<TLeft> left, IEnumerable<TRight> right)
{
    return Zip(left, right, (x, y) => new KeyValuePair<TLeft, TRight>(x, y));
}

// accepts a projection from the caller for each pair
static IEnumerable<TResult> Zip<TLeft, TRight, TResult>(
    this IEnumerable<TLeft> left, IEnumerable<TRight> right,
    Func<TLeft, TRight, TResult> selector)
{
    using(IEnumerator<TLeft> leftE = left.GetEnumerator())
    using (IEnumerator<TRight> rightE = right.GetEnumerator())
    {
        while (leftE.MoveNext() && rightE.MoveNext())
        {
            yield return selector(leftE.Current, rightE.Current);
        }
    }
}

#2


11  

It'll be much simpler to just do it in a plain old for loop instead...

相反,在一个普通的旧循环中做它会简单得多......

for(int i=0; i<ListA.Length; i++)
{
    Console.WriteLine(ListA[i].ToString() + ", " + ListB[i].ToString());
}

#3


5  

You can do it explicit.

你可以明确地做到这一点。

IEnumerator ListAEnum = ListA.GetEnumerator();
IEnumerator ListBEnum = ListB.GetEnumerator();

ListBEnum.MoveNext();
while(ListAEnum.MoveNext()==true)
{
  itemA=ListAEnum.getCurrent();
  itemB=ListBEnum.getCurrent();
  Console.WriteLine(itemA.ToString()+","+itemB.ToString());
}

At least this (or something like this) is what the compiler does for a foreach-loop. I haven't tested it though and I guess some template parameters are missing for the enumerators.

至少这个(或类似的东西)是编译器为foreach循环所做的。我没有测试它,我猜想枚举器缺少一些模板参数。

Just look up GetEnumerator() from List and the IEnumerator-Interface.

只需从List和IEnumerator-Interface中查找GetEnumerator()。

#4


1  

I recommend using plain old for loop, but you should consider different array lengths. So

我建议使用普通的旧for循环,但你应该考虑不同的数组长度。所以

for(int i=0; i<ListA.Length; i++)
{
    Console.WriteLine(ListA[i].ToString() + ", " + ListB[i].ToString());
}

can turn into

可以变成

for(int i = 0; i < Math.Min(ListA.Length, ListB.Lenght); i++)
{
    Console.WriteLine(ListA[i].ToString() + ", " + ListB[i].ToString());
}

or even into

甚至进入

    for(int i = 0; i < Math.Max(ListA.Length, ListB.Lenght); i++)
    {
        string valueA = i < ListA.Length ? listA[i].ToString() : "";
        string valueB = i < ListB.Length ? listB[i].ToString() : "";

        Console.WriteLine(valueA+ ", " + valueB);
    }

#5


1  

I had this same problem but using lists of objects with lists inside of them.. for what its worth, this might help someone with the same issue.

我有同样的问题,但使用列表中包含列表的对象...为了它的价值,这可能会帮助有同样问题的人。

The running time of this isn't very good since IndexOf is O(n), but at the time, I'm dealing with a lot more inner-foreach loops than in this example, so I didn't want to deal with handling iterator variables.

由于IndexOf是O(n),所以运行时间不是很好,但是当时我处理的内部 - foreach循环比这个例子要多得多,所以我不想处理迭代器变量。

At times like this I very much miss PHPs foreach($arrayList as $key => $value) notation... maybe I'm missing something in C#, there's got to be a way to get the index in O(c) time! (sadly this post says no: Getting the array key in a 'foreach' loop)

在这种情况下,我非常想念PHPs foreach($ arrayList为$ key => $ value)表示法...也许我在C#中遗漏了一些东西,必须有一种方法可以在O(c)时间内获得索引! (遗憾的是这篇文章说不:在'foreach'循环中获取数组键)

class Stock {
   string symbol;
   List<decimal> hourlyPrice; // provides a list of 24 decimals
}

// get hourly prices from yesterday and today
List<Stock> stockMondays = Stocks.GetStock("GOOGL,IBM,AAPL", DateTime.Now.AddDay(-1));
List<Stock> stockTuesdays = Stocks.GetStock("GOOGL,IBM,AAPL", DateTime.Now);

try {
    foreach(Stock sMonday in stockMondays) {
        Stock sTuesday = stockTuesday[stockMondays.IndexOf(sMonday)];

        foreach(decimal mondayPrice in sMonday.prices) {
            decimal tuesdayPrice = sTuesday.prices[sMonday.prices.IndexOf(mondayPrice)];
            // do something now
        }

    }
} catch (Exception ex) { // some reason why list counts aren't matching? }

#6


0  

Senthil Kumar's tech blog, has a series covering implementations of (Python) Itertools for C#, including itertools.izip.

Senthil Kumar的科技博客,有一系列文章介绍了C#(Python)Itertools的实现,包括itertools.izip。

From Itertools for C# - Cycle and Zip, you have a solution for any number of iterables (not only List<T>). Note that Zip yields an Array on each iteration:

从Itertools for C# - Cycle和Zip,您可以获得任意数量的迭代(不仅仅是List )的解决方案。请注意,Zip会在每次迭代时生成一个数组:

public static IEnumerable<T[]> Zip<T>(params IEnumerable<T>[] iterables)
{
IEnumerator<T>[] enumerators = Array.ConvertAll(iterables, (iterable) =>   iterable.GetEnumerator());

while (true)
{
   int index = 0;
   T[] values = new T[enumerators.Length];

   foreach (IEnumerator<T> enumerator in enumerators)
   {
       if (!enumerator.MoveNext())
          yield break;

        values[index++] = enumerator.Current;
   }

   yield return values;
}

}

The code gets enumerators for all the iterables, moves all enumerators forward, accumulates their current values into an array and yields the array. It does this until any one of the enumerators runs out of elements.

代码获取所有迭代的枚举器,向前移动所有枚举器,将其当前值累积到数组中并生成数组。它会在任何一个枚举器耗尽元素之前执行此操作。

#7


0  

I have this small function which helps me to iterate through this two list objects. schema is of type SqlData, which is a class that hold three properties. And data is a list that holds values of dynamic type. First I'm iterating through the schema collection and than using the index of item to iterate through the data object.

我有这个小函数,它可以帮助我遍历这两个列表对象。 schema的类型为SqlData,它是一个包含三个属性的类。数据是一个包含动态类型值的列表。首先,我在遍历模式集合,而不是使用item的索引来遍历数据对象。

public List<SqlData> SqlDataBinding(List<SqlData> schema, List<dynamic> data)
{
    foreach (SqlData item in schema)
    {
        item.Values = data[schema.IndexOf(item)];
    }
    return schema
}