Как вы проходите через многомерный массив? - PullRequest
17 голосов
/ 16 февраля 2012
foreach (String s in arrayOfMessages)
{
    System.Console.WriteLine(s);
}

string[,] arrayOfMessages передается в качестве параметра.

Я хочу иметь возможность определить, какие строки из arrayOfMessages[0,i] и arrayOfMessages[n,i], где n - окончательный индексмассива.

Ответы [ 7 ]

36 голосов
/ 16 февраля 2012

Просто используйте две вложенные петли for. Чтобы получить размеры размеров, вы можете использовать GetLength():

for (int i = 0; i < arrayOfMessages.GetLength(0); i++)
{
    for (int j = 0; j < arrayOfMessages.GetLength(1); j++)
    {
        string s = arrayOfMessages[i, j];
        Console.WriteLine(s);
    }
}

Предполагается, что у вас действительно есть string[,]. В .Net также возможно иметь многомерные массивы, которые не индексируются от 0. В этом случае они должны быть представлены как Array в C #, и вам нужно будет использовать GetLowerBound() и GetUpperBound(), чтобы получить границы для каждого измерения.

8 голосов
/ 16 февраля 2012

С вложенным циклом:

for (int row = 0; row < arrayOfMessages.GetLength(0); row++)
{
   for (int col = 0; col < arrayOfMessages.GetLength(1); col++)
   {
      string message = arrayOfMessages[row,col];
      // use the message
   }    
}
7 голосов
/ 16 февраля 2012

Не использовать foreach - использовать вложенные циклы for, по одному для каждого измерения массива.

Количество элементов в каждом измерении можно получить с помощью GetLength method.

См. Многомерные массивы (Руководство по программированию в C #) в MSDN.

2 голосов
/ 07 ноября 2017

Похоже, вы нашли ответ, подходящий для вашей проблемы, но поскольку заголовок запрашивает многомерный массив (который я прочитал как 2 или более ), и это первый результат поиска, который я получил, когда В поисках этого я добавлю свое решение:

public static class MultidimensionalArrayExtensions
{
    /// <summary>
    /// Projects each element of a sequence into a new form by incorporating the element's index.
    /// </summary>
    /// <typeparam name="T">The type of the elements of the array.</typeparam>
    /// <param name="array">A sequence of values to invoke the action on.</param>
    /// <param name="action">An action to apply to each source element; the second parameter of the function represents the index of the source element.</param>
    public static void ForEach<T>(this Array array, Action<T, int[]> action)
    {
        var dimensionSizes = Enumerable.Range(0, array.Rank).Select(i => array.GetLength(i)).ToArray();
        ArrayForEach(dimensionSizes, action, new int[] { }, array);
    }
    private static void ArrayForEach<T>(int[] dimensionSizes, Action<T, int[]> action, int[] externalCoordinates, Array masterArray)
    {
        if (dimensionSizes.Length == 1)
            for (int i = 0; i < dimensionSizes[0]; i++)
            {
                var globalCoordinates = externalCoordinates.Concat(new[] { i }).ToArray();
                var value = (T)masterArray.GetValue(globalCoordinates);
                action(value, globalCoordinates);
            }
        else
            for (int i = 0; i < dimensionSizes[0]; i++)
                ArrayForEach(dimensionSizes.Skip(1).ToArray(), action, externalCoordinates.Concat(new[] { i }).ToArray(), masterArray);
    }

    public static void PopulateArray<T>(this Array array, Func<int[], T> calculateElement)
    {
        array.ForEach<T>((element, indexArray) => array.SetValue(calculateElement(indexArray), indexArray));
    }
}

Пример использования:

var foo = new string[,] { { "a", "b" }, { "c", "d" } };
foo.ForEach<string>((value, coords) => Console.WriteLine("(" + String.Join(", ", coords) + $")={value}"));
// outputs:
// (0, 0)=a
// (0, 1)=b
// (1, 0)=c
// (1, 1)=d

// Gives a 10d array where each element equals the sum of its coordinates:
var bar = new int[4, 4, 4, 5, 6, 5, 4, 4, 4, 5];
bar.PopulateArray(coords => coords.Sum());

Общая идея состоит в том, чтобы проходить через измерения. Я уверен, что функции не получат награды за эффективность, но он работает как одноразовый инициализатор для моей решетки и поставляется с достаточно симпатичным ForEach, который предоставляет значения и индексы. Основной недостаток, который я не решил, - заставить его автоматически распознавать T из массива, поэтому требуется некоторая осторожность, когда речь идет о безопасности типов.

1 голос
/ 16 февраля 2012

Примерно так будет работать:

int length0 = arrayOfMessages.GetUpperBound(0) + 1;
int length1 = arrayOfMessages.GetUpperBound(1) + 1;

for(int i=0; i<length1; i++) { string msg = arrayOfMessages[0, i]; ... }
for(int i=0; i<length1; i++) { string msg = arrayOfMessages[length0-1, i]; ... }
0 голосов
/ 31 декабря 2018

Более функциональным подходом будет использование LINQ, который я всегда нахожу лучше, чем циклы. Это делает код более понятным и понятным. В приведенном ниже фрагменте кода показано одно из решений с использованием синтаксиса Method или Fluent LINQ.

string[,] arrayOfMessages = new string[3, 2] { { "Col1","I am message 1" }, { "Col2", "I am message 2" }, { "Col3", "I am message 3" } };
var result = arrayOfMessages.Cast<string>()
                            .Where((msg, index) => index % 2 > 0);

foreach (var msg in result)
{
    Console.WriteLine(msg);
}

Методы расширения LINQ недоступны для многомерных массивов, поскольку они не реализуют интерфейс IEnumerable<T>. Вот где Cast<T> входит в картину. Он в основном сводит весь массив в IEnumerable<T>. В нашем случае это сгладит многомерный массив в IEnumerable<string> что-то вроде:

{ "Col1", "I am message 1", "Col2", "I am message 2", "Col3", "I am message 3" }

Вы также можете использовать OfType<T> вместо Cast<T>. Единственное различие между ними заключается в том, что в случае коллекций со смешанными типами данных, в то время как OfType<T> игнорирует значения, которые невозможно преобразовать, Cast<T> вызовет исключение InValidCastException.

Далее, все, что нам нужно сделать, это применить оператор LINQ, который игнорирует (или отфильтровывает) значения при четных индексах. Поэтому мы используем перегрузку оператора Where, делегат Func которого имеет тип Func<TSource, int, bool>, где TSource - это каждый элемент в коллекции, int - это индекс элемента в коллекции, а bool - это тип возврата.

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

0 голосов
/ 06 сентября 2017

Вы можете использовать приведенный ниже код для запуска многомерных массивов.

foreach (String s in arrayOfMessages)
{
    System.Console.WriteLine("{0}",s);
}
...