Iterieren Sie mehrdimensionales Array mit verschachtelter Foreach-Anweisung

79

Ich denke, das ist vielleicht eine ziemlich einfache Frage, aber ich habe es noch nicht herausgefunden. Wenn ich ein zweidimensionales Array wie dieses habe:

int[,] array = new int[2,3] { {1, 2, 3}, {4, 5, 6} };

Was ist der beste Weg, um jede Dimension des Arrays mit einer verschachtelten foreach- Anweisung zu durchlaufen ?

Tyler Murry
quelle
Muss es sich um ein zweidimensionales Array handeln, oder können Sie ein Array von Arrays verwenden?
Matthew Flaschen

Antworten:

130

Wenn Sie über jedes Element im Array iterieren möchten, als wäre es ein abgeflachtes Array, können Sie einfach Folgendes tun:

foreach (int i in array) {
    Console.Write(i);
}

was würde drucken

123456

Wenn Sie auch die x- und y-Indizes kennen möchten, müssen Sie Folgendes tun:

for (int x = 0; x < array.GetLength(0); x += 1) {
    for (int y = 0; y < array.GetLength(1); y += 1) {
        Console.Write(array[x, y]);
    }
}

Alternativ können Sie stattdessen ein gezacktes Array (ein Array von Arrays) verwenden:

int[][] array = new int[2][] { new int[3] {1, 2, 3}, new int[3] {4, 5, 6} };
foreach (int[] subArray in array) {
    foreach (int i in subArray) {
        Console.Write(i);
    }
}

oder

int[][] array = new int[2][] { new int[3] {1, 2, 3}, new int[3] {4, 5, 6} };
for (int j = 0; j < array.Length; j += 1) {
    for (int k = 0; k < array[j].Length; k += 1) {
        Console.Write(array[j][k]);
    }
}
ICR
quelle
1
Nachdem ich den Fehler meiner Wege gesehen habe (z. B. den Versuch, ein 2D-Array wie ein gezacktes Array zu verwenden), stimme ich zu, dass der beste Weg, diese Liste zu durchlaufen, genau so ist, wie Sie es in Ihrem ersten Beispiel haben. Sie erhalten die Abstimmung aufgrund Ihrer Bereitschaft, über die Antwort hinauszugehen und andere Optionen anzugeben.
Tyler Murry
Warum ist das 2-Dim-Array abgeflacht?
Sipo
C # = es funktioniert immer nur. C ++ = funktioniert nicht, bevor Sie etwas Zeit verschwenden.
jw_
21

Hier erfahren Sie, wie Sie jedes Element in einem zweidimensionalen Array besuchen. Ist es das, wonach du gesucht hast?

for (int i=0;i<array.GetLength(0);i++)
{
    for (int j=0;j<array.GetLength(1);j++)
    {
        int cell = array[i,j];
    }
}
Daniel Plaisted
quelle
1
Ich hatte auf eine foreach- Implementierung gehofft , wenn das möglich ist?
Tyler Murry
6

Bei mehrdimensionalen Arrays können Sie dieselbe Methode verwenden, um die Elemente zu durchlaufen, z. B.:

int[,] numbers2D = new int[3, 2] { { 9, 99 }, { 3, 33 }, { 5, 55 } };
foreach (int i in numbers2D)
{
    System.Console.Write("{0} ", i);
}

Die Ausgabe dieses Beispiels lautet:

9 99 3 33 5 55

Verweise


In Java sind mehrdimensionale Arrays Arrays von Arrays. Daher funktioniert Folgendes:

    int[][] table = {
            { 1, 2, 3 },
            { 4, 5, 6 },
    };
    for (int[] row : table) {
        for (int el : row) {
            System.out.println(el);
        }
    }
Polygenschmierstoffe
quelle
3
C # hat mehrdimensionale und gezackte Arrays als separate Konzepte, wobei int[,]es sich um ein zweidimensionales Array und int[][]ein gezacktes Array von Arrays handelt und nicht jedes Array die gleiche Länge haben muss. Sie können auf dem gezackten Array leicht einen Foreach durchführen, aber ein 2D-Array ist nicht dieselbe Art von Struktur. In jedem Fall passt Ihr zweites Snippet nicht zu diesem Problem, das erste Snippet ist nicht verschachtelt.
Anthony Pegram
4

Ich weiß, dass dies ein alter Beitrag ist, aber ich habe ihn über Google gefunden, und nachdem ich damit gespielt habe, denke ich, dass ich eine einfachere Lösung habe. Wenn ich falsch liege, weisen Sie bitte darauf hin, denn ich würde es gerne wissen, aber dies hat zumindest für meine Zwecke funktioniert (es basiert auf der Antwort von ICR):

for (int x = 0; x < array.GetLength(0); x++)
{
    Console.Write(array[x, 0], array[x,1], array[x,2]);
}

Da beide Dimensionen begrenzt sind, kann jede einfache Zahl sein und somit eine verschachtelte for-Schleife vermeiden. Ich gebe zu, dass ich neu in C # bin. Wenn es einen Grund gibt, dies nicht zu tun, sagen Sie mir bitte ...

Keven M.
quelle
1
Dies setzt die Länge der 2. Dimension voraus. Sie kodieren die Annahme, dass die zweite Dimension immer die Länge 3 hat, was möglicherweise der Fall ist oder nicht. Wenn es nicht 3 ist, sondern beispielsweise 50, werden Sie viel kopieren / einfügen und Ihren Code unlesbar machen. :)
Adam Lear
@AnnaLear Die Annahme ist nicht unbedingt falsch, Sie könnten eine Matrix mit einer genau definierten Länge wie 15x15 Scrabble Board verarbeiten
Jaycee
3

Das 2D-Array in C # eignet sich nicht gut für verschachtelte Foreachs. Es entspricht nicht einem gezackten Array (einem Array von Arrays). Sie könnten so etwas tun, um einen foreach zu verwenden

foreach (int i in Enumerable.Range(0, array.GetLength(0)))
    foreach (int j in Enumerable.Range(0, array.GetLength(1)))
        Console.WriteLine(array[i, j]);

Sie würden jedoch weiterhin i und j als Indexwerte für das Array verwenden. Die Lesbarkeit bleibt besser erhalten, wenn Sie forstattdessen nur die Garten-Sortenschleife wählen.

Anthony Pegram
quelle
1
Dies ist eine schreckliche Mutation eines klassischen, einfachen und verständlichen Konstrukts. Wenn Ihr Code dies enthält, müssen Sie wirklich denken: "Hey, das funktioniert, aber ... wie wäre es nicht?" (Ich bin mir sehr wohl bewusst, dass dies in der Python-Familie idiomatisch ist. Allerdings - Dies ist C #.)
Rubys
@ Rubys, das ist auch in Python nicht idiomatisch. Es ist sehr unpythonisch, die Indizes abzurufen und dann mit auf die Liste zuzugreifen []. Es ist idiomatisch, Python direkt über Werte zu iterieren. Beachten Sie auch, dass es in Python keine mehrdimensionalen Arrays oder Listen gibt (nur gezackt).
Matthew Flaschen
@ Matthew: Ich habe Python vielleicht mit einer anderen Sprache verwechselt, ich kenne meine Arme nicht wirklich von meinen Beinen in der Scripting-Familie (was ich wohl in der Python-Familie gemeint habe)
Rubys
2

Zwei Wege:

  1. Definieren Sie das Array als gezacktes Array und verwenden Sie verschachtelte foreachs.
  2. Definieren Sie das Array normal und verwenden Sie foreach für das gesamte Objekt.

Beispiel für # 2:

int[,] arr = { { 1, 2 }, { 3, 4 } };
foreach(int a in arr)
    Console.Write(a);

Die Ausgabe wird 1234 sein. genau das gleiche wie i von 0 bis n und j von 0 bis n.

Rubys
quelle
2

Sie können eine Erweiterungsmethode wie die folgende verwenden:

internal static class ArrayExt
{
    public static IEnumerable<int> Indices(this Array array, int dimension)
    {
        for (var i = array.GetLowerBound(dimension); i <= array.GetUpperBound(dimension); i++)
        {
            yield return i;
        }
    }
}

Und dann:

int[,] array = { { 1, 2, 3 }, { 4, 5, 6 } };
foreach (var i in array.Indices(0))
{
    foreach (var j in array.Indices(1))
    {
        Console.Write(array[i, j]);
    }

    Console.WriteLine();
}

Es ist etwas langsamer als die Verwendung für for-Schleifen, aber in den meisten Fällen wahrscheinlich kein Problem. Ich bin mir nicht sicher, ob es die Dinge lesbarer macht.

Beachten Sie, dass c # -Arrays nicht auf Null basieren können, sodass Sie eine for-Schleife wie die folgende verwenden können:

int[,] array = { { 1, 2, 3 }, { 4, 5, 6 } };
for (var i = array.GetLowerBound(0); i <= array.GetUpperBound(0); i++)
{
    for (var j= array.GetLowerBound(1); j <= array.GetUpperBound(1); j++)
    {
        Console.Write(array[i, j]);
    }

    Console.WriteLine();
}
Johan Larsson
quelle
komisch ... was ist nicht nullbasiert?
Drzaus
Ich glaube, ich habe beim Interoping mit Excel eine Nicht-Null-Basis gesehen. Es ist nicht üblich, aber vielleicht gut, sich dessen bewusst zu sein.
Johan Larsson
1

Wie an anderer Stelle erwähnt, können Sie einfach über das Array iterieren und es werden alle Ergebnisse in der Reihenfolge über alle Dimensionen hinweg erzeugt. Wenn Sie jedoch auch die Indizes kennen möchten, können Sie diese verwenden - http://blogs.msdn.com/b/ericlippert/archive/2010/06/28/computing-a-cartesian-product-with- linq.aspx

dann mache ich so etwas wie:

var dimensionLengthRanges = Enumerable.Range(0, myArray.Rank).Select(x => Enumerable.Range(0, myArray.GetLength(x)));
var indicesCombinations = dimensionLengthRanges.CartesianProduct();

foreach (var indices in indicesCombinations)
{
    Console.WriteLine("[{0}] = {1}", string.Join(",", indices), myArray.GetValue(indices.ToArray()));
}
Daniel Smith
quelle
1

Verwenden Sie LINQ .Cast<int>(), um 2D-Arrays in zu konvertieren IEnumerable<int>.

LINQPad-Beispiel:

var arr = new int[,] { 
  { 1, 2, 3 }, 
  { 4, 5, 6 } 
};

IEnumerable<int> values = arr.Cast<int>();
Console.WriteLine(values);

Ausgabe:

Die Sequenz ist 1,2,3,4,5,6

Angularsen
quelle
0

Sie können auch Enumeratoren verwenden. Jeder Array-Typ einer beliebigen Dimension unterstützt die Array.GetEnumerator-Methode. Die einzige Einschränkung ist, dass Sie sich mit Boxen / Unboxing befassen müssen. Der Code, den Sie schreiben müssen, ist jedoch ziemlich trivial.

Hier ist der Beispielcode:

class Program
{
    static void Main(string[] args)
    {
        int[,] myArray = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 } };
        var e = myArray.GetEnumerator();

        e.Reset();

        while (e.MoveNext())
        {
            // this will output each number from 1 to 6. 
            Console.WriteLine(e.Current.ToString());
        }

        Console.ReadLine();
    }
}
code4life
quelle
Abstimmung -1 ... Ich zitiere msdnUsing foreach is recommended, instead of directly manipulating the enumerator.
Ivan
0
int[,] arr =  { 
                {1, 2, 3},
                {4, 5, 6},
                {7, 8, 9}
              };
 for(int i = 0; i < arr.GetLength(0); i++){
      for (int j = 0; j < arr.GetLength(1); j++)
           Console.Write( "{0}\t",arr[i, j]);
      Console.WriteLine();
    }

output:  1  2  3
         4  5  6
         7  8  9
Sohel Ahmed
quelle
0

Ich suchte nach einer Lösung, um ein Array eines unbekannten Ranges zur Kompilierungszeit mit Zugriff auf alle eingestellten Elementindizes aufzulisten. Ich habe Lösungen mit Ertrag gesehen, aber hier ist eine andere Implementierung ohne Ertrag. Es ist in der alten Schule minimalistisch. In diesem Beispiel druckt AppendArrayDebug () einfach alle Elemente in den StringBuilder-Puffer.

public static void AppendArrayDebug ( StringBuilder sb, Array array )
{
    if( array == null || array.Length == 0 )
    {
        sb.Append( "<nothing>" );
        return;
    }

    int i;

    var rank = array.Rank;
    var lastIndex = rank - 1;

    // Initialize indices and their boundaries
    var indices = new int[rank];
    var lower = new int[rank];
    var upper = new int[rank];
    for( i = 0; i < rank; ++i )
    {
        indices[i] = lower[i] = array.GetLowerBound( i );
        upper[i] = array.GetUpperBound( i );
    }

    while( true )
    {
        BeginMainLoop:

        // Begin work with an element

        var element = array.GetValue( indices );

        sb.AppendLine();
        sb.Append( '[' );
        for( i = 0; i < rank; ++i )
        {
            sb.Append( indices[i] );
            sb.Append( ' ' );
        }
        sb.Length -= 1;
        sb.Append( "] = " );
        sb.Append( element );

        // End work with the element

        // Increment index set

        // All indices except the first one are enumerated several times
        for( i = lastIndex; i > 0; )
        {
            if( ++indices[i] <= upper[i] )
                goto BeginMainLoop;
            indices[i] = lower[i];
            --i;
        }

        // Special case for the first index, it must be enumerated only once
        if( ++indices[0] > upper[0] )
            break;
    }
}

Das folgende Array erzeugt beispielsweise die folgende Ausgabe:

var array = new [,,]
{
    { {  1,  2,  3 }, {  4,  5,  6 }, {  7,  8,  9 }, { 10, 11, 12 } },
    { { 13, 14, 15 }, { 16, 17, 18 }, { 19, 20, 21 }, { 22, 23, 24 } }
};

/*
Output:

[0 0 0] = 1
[0 0 1] = 2
[0 0 2] = 3
[0 1 0] = 4
[0 1 1] = 5
[0 1 2] = 6
[0 2 0] = 7
[0 2 1] = 8
[0 2 2] = 9
[0 3 0] = 10
[0 3 1] = 11
[0 3 2] = 12
[1 0 0] = 13
[1 0 1] = 14
[1 0 2] = 15
[1 1 0] = 16
[1 1 1] = 17
[1 1 2] = 18
[1 2 0] = 19
[1 2 1] = 20
[1 2 2] = 21
[1 3 0] = 22
[1 3 1] = 23
[1 3 2] = 24
*/
C0DEF52
quelle