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
I recommend using plain old for loop, but you should consider different array lengths. So
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);
}
[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).
It sounds like you need the missing Zip
operator; you can spoof it:
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);
}
}
}
Senthil Kumar's tech blog, has a series covering implementations of (Python) Itertools for C#, including 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:
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.
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.
Just look up GetEnumerator() from List and the IEnumerator-Interface.
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());
}
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.
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)
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? }