использование цикла foreach для двух списков в С# для получения значений списков

List<String> listA = new List<string> { "A1", "A2" };
List<String> listB = new List<string> { "B1", "B2" };

for(int i = 0; i < listA.Count; i++)
{
    text += listA[i] + " and " + listB[i];
}

Как я могу сделать это, используя цикл foreach?


person Hina Hanif    schedule 10.07.2012    source источник
comment
зачем тебе это?   -  person Samson    schedule 10.07.2012
comment
stackoverflow.com/questions/1955766/   -  person Samson    schedule 10.07.2012
comment
вы не можете сделать это простым и эффективным способом. цикл for выглядит нормально, но используйте построитель строк   -  person Amiram Korach    schedule 10.07.2012


Ответы (7)


Вы можете использовать Linq и метод Zip:

List<String> listA = new List<string> { "A1", "A2" };
List<String> listB = new List<string> { "B1", "B2" };

foreach (var pair in listA.Zip(listB, (a,b) => new {A = a, B = b}))
{
    text += pair.A + " and " + pair.B;
}
person nemesv    schedule 10.07.2012
comment
Из любопытства, что произойдет, если listB короче, чем listA? - person Alex; 10.07.2012
comment
@Alex Я считаю, что он перестает повторяться на кратчайшем перечислении. Связанная документация выше подтверждает это в примечаниях. - person Adam Houldsworth; 10.07.2012
comment
@Alex из msdn: если входные последовательности не имеют одинакового количества элементов, метод объединяет элементы, пока не достигнет конца одной из последовательностей. Например, если в одной последовательности три элемента, а в другой — четыре, результирующая последовательность будет состоять только из трех элементов. - person nemesv; 10.07.2012
comment
Я бы +2 этому, если бы мог ... стыдно за то, что я не исследовал язык должным образом, я не знал об этом расширении - person Alex; 10.07.2012
comment
я пытаюсь это сделать, но listA.Zip не в С#. почтовый индекс - person Hina Hanif; 10.07.2012
comment
@HinaHanif Zip — это метод расширения, представленный в .net 3.5, вам нужно использовать его пространство имен: поэтому добавьте эту строку в исходный файл: using System.Linq; - person nemesv; 10.07.2012

Вы не можете сделать это с foreach лучше, чем вы уже делаете это с for - foreach на самом деле предназначен только для хорошей работы, когда есть только одна последовательность для перечисления.

Однако вы можете сделать это очень удобно с помощью LINQ:

text = string.Join("", listA.Zip(listB, (a, b) => a + " and " + b));

Для этого требуется .NET 4 как для Zip, так и для конкретная перегрузка string.Join.

person Jon    schedule 10.07.2012

Другой способ сделать это с помощью простого Enumerator:

IEnumerator<string>  enumerator = listB.GetEnumerator(); 
enumerator.MoveNext();
foreach(var stra in listA) {
    text += stra + " and " + enumerator.Current.ToString() + ", ";
    enumerator.MoveNext();
}
person Tigran    schedule 10.07.2012

Используйте LINQ

string text = listA.Zip(listB, (a, b) => new {A = a, B = b}).Aggregate("", (current, pair) => current + (pair.A + " and " + pair.B));
person Ria    schedule 10.07.2012

И если вы не хотите использовать LINQ и хотите, чтобы они выполнялись параллельно, у вас есть несколько вариантов — с новыми классами и т. д., как показано ниже, ИЛИ вы можете использовать foreach, но только для одного из списков, например это:

List<String> listA = new List<string> { "A1", "A2" };
List<String> listB = new List<string> { "B1", "B2" };
string text = "";
int i = 0;
foreach (string s in listA) {
   text += s + " and " + listB [i++] + "\n";
}
Console.WriteLine (text);

или сделать его немного лучше, используя GetEnumerator:

List<String> listA = new List<string> { "A1", "A2" };
List<String> listB = new List<string> { "B1", "B2" };
string text = "";       
List<string>.Enumerator e = listB.GetEnumerator ();
foreach (string s in listA) {
   e.MoveNext ();
   text += s + " and " + e.Current + "\n";
}
Console.WriteLine (text);

также вы можете создать себе метаколлекцию Enumberable, которая всегда будет возвращать из этого простой массив строк - для этого вам нужно будет создать Enumerator и класс, производный от IEnumerable:

Сначала перечислитель:

private class DoubleStringEnumerator : IEnumerator
{
    private DoubleString _elemList;
    private int _index;
    public DoubleStringEnumerator(DoubleString doubleStringObjt)
    {
        _elemList = doubleStringObjt;
        _index = -1;
    }
    public void Reset()
    {
        _index = -1;
    }
    public object Current {
        get {
            return _elemList.getNext();
        }
    }
    public bool MoveNext ()
    {
        _index++;
        if (_index >= _elemList.Length)
            return false;
        else
            return true;
    }
}

Метод Current на самом деле не соответствует своему названию в данном примере, но он предназначен для обучения.

Теперь класс:

public class DoubleString : IEnumerable
{
    public int Length;
    List<String> listA;
    List<String> listB;
    List<string>.Enumerator eA,eB;
    public DoubleString(List<String> newA,List<String> newB)
    {
        if(newA.Count != newB.Count) {
            throw new Exception("Lists lengths must be the same");    
        }
        listA = newA;
        listB = newB;
        eA = listA.GetEnumerator ();
        eB = listB.GetEnumerator ();
        Length = listA.Count;
    }
    IEnumerator IEnumerable.GetEnumerator ()
    {
        return (IEnumerator)new DoubleStringEnumerator(this);
    }
    public string[] getNext ()
    {
        eA.MoveNext ();
        eB.MoveNext ();
        return new string[] {eA.Current ,eB.Current };
    }
}

И сам код:

List<String> listA = new List<string> { "A1", "A2" };
List<String> listB = new List<string> { "B1", "B2" };               
DoubleString newDoubleString = new DoubleString (listA, listB);             
string text = "";
foreach (string[] s in newDoubleString) {
    text += s[0] + " and " + s[1] + "\n";
}
Console.WriteLine (text);

Конечно, лучше использовать LINQ. Код не оптимизирован, но у меня не было с собой компилятора, так что пишу из головы - надеюсь, это прояснит некоторые вещи. Не стесняйтесь задавать вопросы.

person Bartosz Pachołek    schedule 10.07.2012

Вот решение с использованием foreach:

string text = null;
int cnt = 0;

List<String> listA = new List<string> { "A1", "A2" };
List<String> listB = new List<string> { "B1", "B2" };

foreach (string i in listA)
  {
         text += listA[cnt] + " and " + listB[cnt];
         cnt++;
  }

С уважением и благодарностью,
Субханкар

person Subhankar    schedule 10.07.2012
comment
почему вы используете listA[cnt] вместо i? - person Francesco Baruchelli; 10.07.2012
comment
@Francesco, разве вы не видите, что i является строковой переменной, и мы не можем получить доступ к индексу массива, используя строку. - person Subhankar; 10.07.2012
comment
@FrancescoBaruchelli, можем ли мы получить доступ к индексу массива, используя строку? - person Subhankar; 10.07.2012
comment
да, это строка, а listA[cnt] это...? Я имею в виду, почему вы тратите время на доступ к массиву, чтобы получить то, что у вас уже есть? - person Francesco Baruchelli; 10.07.2012
comment
@FrancescoBaruchelli, но если я не получу его по индексу в блоке foreach, то как я могу объединить обе строки, такие как A1 и B1, A2 и B2 .. - person Subhankar; 10.07.2012

person    schedule
comment
Это просто перефразировка повторяющегося вопроса, упомянутого в комментариях. - person Adam Houldsworth; 10.07.2012