我有两个长度相同的列表,是否可以一次循环这两个列表?
我正在寻找正确的语法来执行以下操作
foreach itemA, itemB in ListA, ListB
{
Console.WriteLine(itemA.ToString()+","+itemB.ToString());
}
Run Code Online (Sandbox Code Playgroud)
你认为这在C#中有可能吗?如果是的话,lambda表达式与此相当的是什么?
Mar*_*ell 26
[编辑]:澄清; 这在通用LINQ/IEnumerable<T>context中非常有用,在这种情况下你不能使用索引器,因为a:它不存在于可枚举中,而b:你不能保证你可以多次读取数据.由于OP提到了lambdas,所以LINQ可能不会太远(是的,我确实意识到LINQ和lambdas不是完全相同的事情).
听起来你需要缺少的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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
jce*_*gin 11
相反,在一个普通的旧循环中做它会简单得多......
for(int i=0; i<ListA.Length; i++)
{
Console.WriteLine(ListA[i].ToString() + ", " + ListB[i].ToString());
}
Run Code Online (Sandbox Code Playgroud)
LINQ 现在有一个内置的 Zip 方法,因此您无需创建自己的方法。生成的序列与最短的输入一样长。Zip 目前(从 .NET Core 3.0 开始)有 2 个重载。更简单的返回一个元组序列。它让我们可以生成一些非常简洁的代码,接近原始请求:
int[] numbers = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three" };
foreach (var (number, word) in numbers.Zip(words))
Console.WriteLine($"{number}, {word}");
// 1, one
// 2, two
// 3, three
Run Code Online (Sandbox Code Playgroud)
或者,同样的事情,但没有元组解包:
foreach (var item in numbers.Zip(words))
Console.WriteLine($"{item.First}, {item.Second}");
Run Code Online (Sandbox Code Playgroud)
另一个重载(早于 Core 3.0 出现)采用映射函数,使您可以更好地控制结果。此示例返回字符串序列,但您可以返回任何内容的序列(例如某些自定义类)。
var numbersAndWords = numbers.Zip(words, (number, word) => $"{number}, {word}");
foreach (string item in numbersAndWords)
Console.WriteLine(item);
Run Code Online (Sandbox Code Playgroud)
如果您在常规对象上使用 LINQ(而不是使用它来生成 SQL),您还可以查看MoreLINQ,它提供了多种压缩方法。这些方法中的每一个最多需要 4 个输入序列,而不仅仅是 2 个:
EquiZip- 如果输入序列的长度不同,则会引发异常。
ZipLongest- 生成的序列将始终与最长的输入序列一样长,其中每个较短序列元素类型的默认值用于填充。
ZipShortest- 生成的序列与最短的输入序列一样短。
请参阅他们的示例和/或测试以了解用法。MoreLINQ 的压缩似乎出现在常规 LINQ 之前,因此如果您坚持使用旧版本的 .NET,它可能是一个不错的选择。
小智 5
你可以明确地做到这一点.
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());
}
Run Code Online (Sandbox Code Playgroud)
至少这个(或类似的东西)是编译器为foreach循环所做的事情.我没有测试它,我猜测枚举器缺少一些模板参数.
只需从List和IEnumerator-Interface中查找GetEnumerator().
| 归档时间: |
|
| 查看次数: |
13268 次 |
| 最近记录: |