Как я могу перебрать два IEnumerables одновременно в .NET 2 - PullRequest
2 голосов
/ 03 февраля 2011

РЕДАКТИРОВАТЬ: Я разделил это на два вопроса:

  • Итерация по двум спискам, заканчивающимся на более короткий
  • Перебирать несколько списков, пока не будет достигнут последний элемент самого длинного списка

Предположим, у меня есть два 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.

Ответы [ 5 ]

5 голосов
/ 03 февраля 2011

Подсказка для .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
}
4 голосов
/ 03 февраля 2011

Как не-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;
  }
}

Edit (для вашего нового условия), чтобы выполнить итерацию сзначения по умолчанию до последнего перечисления:

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);
  }
}
1 голос
/ 03 февраля 2011
1 голос
/ 03 февраля 2011

Это можно сделать, выполнив вручную то, что внутренний цикл 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
    }
}
0 голосов
/ 03 февраля 2011

Я не уверен, что понимаю вопрос / контекст.

Подойдет ли вам словарь?

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;
        }
    }
...