Как делают меня 'foreach' через двухмерную антенную решетку?

У меня есть двухмерная антенная решетка,

string[,] table = {
                       { "aa", "aaa" },
                       { "bb", "bbb" }
                   };

И я хотел бы foreach через него как это,

foreach (string[] row in table)
{
    Console.WriteLine(row[0] + " " + row[1]);
}

Но, я получаю ошибку:

Не может преобразовать строку типа для строкового представления []

Существует ли способ, которым я могу достигнуть того, что я хочу, т.е. выполняю итерации через первый размер массива с переменной итератора возврата меня одномерный массив для той строки?

45
задан Peter Mortensen 7 May 2017 в 14:35
поделиться

6 ответов

Если вы определяете свой массив следующим образом:

string[][] table = new string[][] { new string[] { "aa", "aaa" }, new string[]{ "bb", "bbb" } };

Тогда вы можете использовать для него цикл foreach.

25
ответ дан 26 November 2019 в 20:52
поделиться

Многомерные массивы нельзя перечислить. Просто повторите старый добрый способ:

for (int i = 0; i < table.GetLength(0); i++)
{
    Console.WriteLine(table[i, 0] + " " + table[i, 1]);
}
60
ответ дан 26 November 2019 в 20:52
поделиться
string[][] table = { ... };
3
ответ дан 26 November 2019 в 20:52
поделиться

Как предлагали другие, вы можете использовать вложенные циклы for или повторно объявить свой многомерный массив как зубчатый.

Однако я думаю, что стоит отметить, что многомерные массивы перечислимы, но не так, как вы хотите. Например:

string[,] table = {
                      { "aa", "aaa" },
                      { "bb", "bbb" }
                  };

foreach (string s in table)
{
    Console.WriteLine(s);
}

/* Output is:
  aa
  aaa
  bb
  bbb
*/
26
ответ дан 26 November 2019 в 20:52
поделиться

ОБНОВЛЕНИЕ : у меня было немного свободного времени, так что ... Я пошел дальше и конкретизировал эту идею. Смотрите код ниже.


Вот немного сумасшедший ответ:

Вы можете делать то, что ищете - по сути, обрабатывать двумерный массив как таблицу со строками - написав статический метод (возможно, метод расширения), который принимает T [,] и возвращает IEnumerable . Однако для этого потребуется скопировать каждую «строку» базовой таблицы в новый массив.

Возможно, лучшим (хотя и более сложным) подходом было бы написание класса, реализующего IList как оболочку вокруг единственной «строки» двумерного массива (вы, вероятно, установите IsReadOnly в значение true и просто реализуйте геттер для свойства this [int] и, возможно, Count и GetEnumerator ; все остальное может выбросить a NotSupportedException ). Тогда ваш статический метод / метод расширения может вернуть IEnumerable > и обеспечить отложенное выполнение.

Таким образом, вы могли писать код, очень похожий на ваш:

foreach (IList<string> row in table.GetRows()) // or something
{
    Console.WriteLine(row[0] + " " + row[1]);
}

Просто мысль.


Предложение по реализации:

public static class ArrayTableHelper {
    public static IEnumerable<IList<T>> GetRows<T>(this T[,] table) {
        for (int i = 0; i < table.GetLength(0); ++i)
            yield return new ArrayTableRow<T>(table, i);
    }

    private class ArrayTableRow<T> : IList<T> {
        private readonly T[,] _table;
        private readonly int _count;
        private readonly int _rowIndex;

        public ArrayTableRow(T[,] table, int rowIndex) {
            if (table == null)
                throw new ArgumentNullException("table");

            if (rowIndex < 0 || rowIndex >= table.GetLength(0))
                throw new ArgumentOutOfRangeException("rowIndex");

            _table = table;
            _count = _table.GetLength(1);
            _rowIndex = rowIndex;
        }

        // I didn't implement the setter below,
        // but you easily COULD (and then set IsReadOnly to false?)
        public T this[int index] {
            get { return _table[_rowIndex, index]; }
            set { throw new NotImplementedException(); }
        }

        public int Count {
            get { return _count; }
        }

        bool ICollection<T>.IsReadOnly {
            get { return true; }
        }

        public IEnumerator<T> GetEnumerator() {
            for (int i = 0; i < _count; ++i)
                yield return this[i];
        }

        // omitted remaining IList<T> members for brevity;
        // you actually could implement IndexOf, Contains, etc.
        // quite easily, though
    }
}

... теперь я думаю, что мне следует дать StackOverflow перерыв на остаток дня;)

15
ответ дан 26 November 2019 в 20:52
поделиться

Помните, что многомерный массив подобен таблице. У вас нет элемента x и элемента y для каждой записи; у вас есть строка в (например) table[1,2].

Таким образом, каждая запись по-прежнему является только одной строкой (в вашем примере), это просто запись в определенном значении x/y. Поэтому, чтобы получить обе записи в table[1, x], вы должны сделать вложенный цикл for. Что-то вроде следующего (не проверялось, но должно быть близко)

for (int x = 0; x < table.Length; x++)
{
    for (int y = 0; y < table.Length; y += 2)
    {
        Console.WriteLine("{0} {1}", table[x, y], table[x, y + 1]);
    }
}
1
ответ дан 26 November 2019 в 20:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: