【问题标题】:How can I iterate over two IEnumerables simultaneously in .NET 2如何在 .NET 2 中同时迭代两个 IEnumerable
【发布时间】:2011-06-20 18:26:16
【问题描述】:

编辑:我把它分成两个问题:

  • 遍历两个以较短的列表结尾的列表
  • 遍历多个列表,直到到达最长列表的最后一个元素

假设我有两个带有许多元素的 IEnumerable。每个 IEnumerable 都有另一个类型 T。

IEnumerable<int> ints=getManyInts();
IEnumerable<string> strings=getSomeStrings();

我想要做的是遍历两个列表,并为每个步骤获取一个包含一个 int 和一个字符串的项目,直到到达最短列表的末尾。

for(Item<int,string> item in Foo.Combine<int,string>(ints, strings))
{
    int i=item.Val1;
    string s=item.Val2;
}

您也可以提示我如何在 .NET 4 中执行此操作。

【问题讨论】:

    标签: .net .net-2.0 foreach ienumerable


    【解决方案1】:

    作为非 LINQ-apprach (.NET 2),这可以像这样进行顶部迭代,直到其中一个枚举完成:

    using (IEnumerator<int> intItem = GetManyInts().GetEnumerator())
    using (IEnumerator<string> stringItem = GetSomeStrings().GetEnumerator()) {
      while (intItem.MoveNext() && stringItem.MoveNext()) {
        int i=intItem.Current;
        string s=stringItem.Current;
      }
    }
    

    编辑(针对您的新条件),使用默认值进行迭代,直到最后一次枚举完成:

    using (IEnumerator<int> intItem = GetManyInts().GetEnumerator())
    using (IEnumerator<string> stringItem = GetSomeStrings().GetEnumerator()) {
      bool hasInt;
      bool hasString;
      while ((hasInt = intItem.MoveNext()) | (hasString = stringItem.MoveNext())) {
        int i=hasInt ? intItem.Current : default(int);
        string s=hasString ? stringItem.Current : default(string);
      }
    }
    

    【讨论】:

    • 您的回答中有一个逻辑错误:||运算符将跳过第二个 MoveNext
    【解决方案2】:

    这可以通过手动执行 for-each 循环在内部执行的操作来完成

    IEnumerable<int> ints=getManyInts();
    IEnumerable<string> strings=getSomeStrings();
    using (IEnumerator<int> intsEnum = ints.GetEnumerator())
    using (IEnumerator<string> stringsEnum = strings.GetEnumerator())
    {
        while (intsEnum.MoveNext() && stringsEnum.MoveNext())
        {
            int i = intsEnum.Current;
            string s = stringsEnum.Current;
        }
    }
    

    编辑最长列表:

    IEnumerable<int> ints=getManyInts();
    IEnumerable<string> strings=getSomeStrings();
    using (IEnumerator<int> intsEnum = ints.GetEnumerator())
    using (IEnumerator<string> stringsEnum = strings.GetEnumerator())
    {
        bool intIsValid = intsEnum.MoveNext()
        bool stringIsValid = stringsEnum.MoveNext()
        while (intIsValid || stringIsValid)
        {
            int i = default(int)
            string s = default(string)
            if(intIsValid)
            {
               i = intsEnum.Current;
               intIsValid = intsEnum.MoveNext();
            }
            if(stringIsValid)
            {
               s = stringsEnum.Current;
               stringIsValid = stringsEnum.MoveNext();
            }
            //code goes here
        }
    }
    

    【讨论】:

      【解决方案3】:
      【解决方案4】:

      我不确定我是否理解问题/上下文。

      使用字典对你有用吗?

      internal static class Foo
          {
              internal static Dictionary<TKey, TValue> Combine<TKey, TValue>
                  ( IList<TKey> keys, IList<TValue> values )
              {
                  var dictionary = new Dictionary<TKey, TValue>();
                  // write your own 'combination' code...
                  for (int i = 0; i < keys.Count && i<values.Count; i++)
                  {
                      dictionary.Add(keys[i], values[i]);
                  }
                  return dictionary;
              }
          }
      
          private static void Main(string[] args)
          {
              // collection initialization and var: .NET 3.0 or higher
              var keys = new List<int> {1, 2, 3, 5, 6, 7, 8, 10, 15, 99};
              var values = new List<string> {"one", "two", "tree", "four"};
      
              var combinded = Foo.Combine<int, string>(keys, values);
              foreach (KeyValuePair<int, string> keyValuePair in combinded)
              {
                  int key = keyValuePair.Key;
                  string value = keyValuePair.Value;
              }
          }
      

      【讨论】:

      • 字典会弄乱顺序并因重复键而失败。
      • 没有。列表非常长(生成或从数据库生成)。我不想把每一项都保存在内存中。
      【解决方案5】:

      .NET 4.0 的提示:

      var result = ints.Zip(strings, (i, s) => new { Key = i, Value = s });
      foreach(var item in result)
      {
          int key = item.Key;
          string value = item.Value;
          // Do something with the kvp
      }
      

      【讨论】:

      • 只回答简短的(.NET 4)部分被认为是懒惰的;-)
      • @TToni,我是开发人员,根据定义是懒惰的 :-)
      • 谢谢。我知道在 .NET 4 中它一定很容易。但不幸的是,我还必须维护一些旧项目。
      • 我认为只提供 .net 4 代码是安全的选择,因为大多数其他人似乎只提供 .net 2 代码。
      猜你喜欢
      • 2011-06-20
      • 1970-01-01
      • 1970-01-01
      • 2023-01-12
      • 1970-01-01
      • 1970-01-01
      • 2016-05-16
      • 2021-04-11
      相关资源
      最近更新 更多