19

我们可以在foreach中使用多个变量吗

foreach (var item1 in collection1;var items2 in collection2)
{

}

我想这样做是因为我需要从数据库中获取两个集合并将它们都附加到 ComboBox。

4

9 回答 9

16

使用 LINQ 连接数组,将结果放入匿名类型,然后遍历生成的集合。

var col = collection1.Join(collection2, x => x, y => y, (x, y) => new { X = x, Y = y });
foreach (var entry in col) {
    // entry.X, entry.Y
}

编辑:

在发布答案时,我假设collection1collection2包含不同的类型。如果它们都包含相同的类型或共享一个共同的基本类型,则有替代方案:

如果要允许重复:

collection1.Concat(collection2); // same type
collection1.select(x => (baseType)x).Concat(collection2.select(x => (baseType)x)); // shared base type

没有重复:

collection1.Union(collection2); // same type
collection1.select(x => (baseType)x).Union(collection2.select(x => (baseType)x)); // shared base type

Form framework 4.0 及以上 Zip 可以替代原来的解决方案:

collection1.Zip(collection2, (x, y) => new { X = x, Y = y });

有关大多数可用 LINQ 功能的概述,请参阅101 LINQ 示例

如果不使用 LINQ,请使用两个分层 foreach 循环(增加交互次数)或一个 foreach 循环来创建中间类型,然后使用第二个循环来遍历中间类型的集合,或者如果集合中的类型相同,则将它们添加到列表中(使用AddRange)然后遍历这个新列表。

多条道路通向一个目标……由您选择一个目标。

于 2013-01-25T06:32:23.850 回答
6

您可以压缩收藏

foreach (var item in collection1.Zip(collection2, (a, b) => new {  A = a, B = b }))
{
  var a = item.A;
  var b = item.B;
  // ...
}

这假定元素在相同位置匹配(例如,collection1 中的第一个元素连接到collecion2 的第一个元素)。这是相当有效的。

于 2013-01-25T06:52:36.620 回答
3

不,您不能在 foreach、in 循环中使用多个变量。检查语言参考。如果每个集合有不同数量的项目会发生什么?

如果要遍历两个集合,请尝试使用联合:

foreach (var item1 in collection1.Union(collection2))
{
   ...
}
于 2013-01-25T06:31:30.157 回答
1

从您的评论来看,我认为您真正想做的不是获得两个集合的笛卡尔积,而是获得两个集合的 [SQL] UNION。你有两个选择:

  1. Concat两个集合:

    foreach(var items in collection1.Concat(collection2)) {}
    
  2. 只需分别添加它们,假设您不需要通过迭代来做任何花哨的事情(可能是最好的/最简单的):

    myComboBox.Items.AddRange(collection1);
    myComboBox.Items.AddRange(collection2);
    

但是,如果您确实需要 [SQL 伪代码] 的 n*m 笛卡尔积collection1 CROSS JOIN collection2,则可以使用两个嵌套的 foreach 语句:

foreach(var item1 in collection1)
foreach(var item2 in collection2)
{
}

或者,您可以在 LINQ 中加入这两者并遍历加入的集合:

foreach(var items in (from i1 in collection1 
                      from i2 in collection2 
                      select Tuple.Create(i1, i2)))
{
}
于 2013-01-25T06:32:45.610 回答
1

foreach 用于枚举集合中的单个项目。所以不,你不能。你必须一个接一个地使用它。最好使用:

void myfunc()
{}

foreach(var item1 in collection1){myfunc();}
foreach(var item2 in collection2){myfunc();}

foreach(var item1 in collection1)
foreach(var item2 in collection2)
{
    myfunc();
}

这将运行 n*m 次。而前面的示例只运行 n+m 次。

于 2013-01-25T06:42:06.100 回答
0

您想将一个集合中的项目与另一个集合中的相应项目配对吗?

foreach (var pair in col1.Zip(col2, (Item1, Item2) => new { Item1, Item2 })
{
    //do something with pair.Item1 and pair.Item2
}

注意:如果第一个系列有 10 件,第二个有 8 个,您将获得 8 双;第一个集合中的最后两个项目将被删除,因为在第二个集合中没有任何东西可以匹配它们。更一般地,迭代次数为Min(col1.Count(), col2.Count()).

您是否要迭代一个集合中的所有项目,然后迭代第二个集合中的所有项目?

foreach (var element in col1.Concat(col2))
{
    //do something with element
}

注意:如果第一个集合有 10 个元素,第二个有 8 个元素,则此循环将执行 18 次,或者更一般地说,迭代次数为col1.Count() + col2.Count().

您想将一个集合中的每个项目与另一个集合中的每个项目配对吗?

foreach (var item1 in col1)
    foreach (var item2 in col2)
    {
         //do something with item1 and item2
    }

注意:这是笛卡尔积,因此毫不奇怪,迭代次数是集合大小的乘积。如果我们有 10 和 8 个项目,循环将执行 80 次。为了一致性起见,这是col1.Count() * col2.Count().

于 2013-01-25T07:28:20.147 回答
0

使用枚举器是最简单的方法。您可以使用这两个集合中的任何一个来获取枚举器并在另一个上运行 foreach。


    public void MatchSentences() {
                string[] OrigSentences = { "hello you", "what are you doing", "hope things are fine" };
                string[] CompareSentences = { "hello you", "what are you doing", "hope things are fine" };
                // Get enumerator on the second collection
                var outputStrEnum = CompareSentences.GetEnumerator();
    
                // Run foreach on the first collection
                foreach (var sentence in OrigSentences) {
                    outputStrEnum.MoveNext();
                    string testAgainst = outputStrEnum.Current.ToString();
                    bool result = sentence.Equals(testAgainst);
                    
                    Assert.IsTrue(result,
                        String.Format(" Expected for '{0}': {1}; Actual: '{2}'",
                                testAgainst, result,sentence) );
                }
    
            }

于 2020-07-03T17:49:24.410 回答
0

您可以使用迭代器:

IEnumerator <Item2Type> item2Itt = Collection2.GetEnumerator();
item2Itt.MoveNext(); // The iterator returned above is BEFORE the first element in the collection.
foreach (Item1Type item1 in collection1)
{
    item1.blahblahblah;
    item2Itt.Current.blahBlahBlah;
    item2Itt.MoveNext();
}
于 2015-08-06T15:48:07.250 回答
0

我认为可以使用这种方式:

List<Type> allOfThem = new List<Type>(); //use proper type for collection
allOfThem.AddRange(collection1);
allOfThem.AddRange(collection2);

foreach (Type item in allOfThem)
{
...
} 
于 2018-12-18T15:41:04.447 回答