web-dev-qa-db-fra.com

Comment passez-vous en boucle dans un tableau multidimensionnel?

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

string[,] arrayOfMessages est transmis en tant que paramètre.

Je veux être capable de déterminer quelles chaînes sont à partir de arrayOfMessages[0,i] et arrayOfMessages[n,i], où n est l'indice final du tableau.

14
orange

Utilisez simplement deux boucles for imbriquées. Pour obtenir les tailles des dimensions, vous pouvez utiliser 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);
    }
}

Cela suppose que vous avez réellement string[,]. Il est également possible d’utiliser des tableaux multidimensionnels non indexés à partir de 0. Dans ce cas, ils doivent être représentés par Array en C # et vous devez utiliser GetLowerBound() et GetUpperBound() pour obtenir les limites de chaque dimension.

34
svick

Avec une boucle imbriquée:

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
Henk Holterman

N'utilisez pas foreach - utilisez des boucles for imbriquées, une pour chaque dimension du tableau.

Vous pouvez obtenir le nombre d'éléments dans chaque dimension avec la méthode GetLength .

Voir Tableaux multidimensionnels (Guide de programmation C #) sur MSDN.

6
Oded

Il semble que vous ayez trouvé une réponse adaptée à votre problème, mais puisque le titre demande un tableau multidimensionnel (que je lis comme 2 ou plus ), et c’est le premier résultat de recherche que j’ai obtenu lors de la recherche, je ajoutera ma solution:

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

Exemple d'utilisation:

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());

L'idée générale est de récidiver à travers les dimensions. Je suis sûr que les fonctions ne seront pas récompensées pour l'efficacité, mais cela fonctionne comme un initialiseur unique pour mon réseau et est fourni avec un ForEach assez joli qui expose les valeurs et les indices. Le principal inconvénient que je n'ai pas résolu consiste à le faire reconnaître automatiquement T dans le tableau. Il faut donc faire preuve de prudence en ce qui concerne le type de sécurité.

2
dananski

Quelque chose comme ça marcherait:

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]; ... }
1
Igor ostrovsky

Une approche plus fonctionnelle consisterait à utiliser LINQ, que je trouve toujours meilleur que les boucles. Cela rend le code plus facile à gérer et à lire. L'extrait de code donné ci-dessous montre l'une des solutions utilisant la syntaxe Method ou 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);
}

Les méthodes d'extension LINQ ne sont pas disponibles pour les tableaux multidimensionnels car elles n'implémentent pas l'interface IEnumerable<T>. C'est là que Cast<T> entre en image. Fondamentalement, tout le tableau est converti en IEnumerable<T>. Dans notre cas, il va aplatir le tableau multi-dimensionnel en IEnumerable<string> quelque chose comme:

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

Vous pouvez également utiliser OfType<T> au lieu de Cast<T>. La seule différence entre eux est que dans le cas de collections avec des types de données mélangés, alors que OfType<T> ignore les valeurs qu'il est impossible de transtyper, Cast<T> lève une exception InValidCastException.

Ensuite, il suffit d’appliquer un opérateur LINQ qui ignore (ou filtre) les valeurs aux indices pairs. Nous utilisons donc une surcharge d'opérateur Where dont le délégué Func est de type Func<TSource, int, bool>, où TSource est chaque élément de la collection, int est l'index de l'élément dans la collection et bool est le type de retour.

Dans l'extrait ci-dessus, j'ai utilisé une expression lambda qui évalue chaque index d'élément et renvoie vrai uniquement s'il s'agit d'un nombre impair.

0
r4k35h

Vous pouvez utiliser le code ci-dessous pour exécuter des tableaux multidimensionnels.

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