Prüfen, ob ein 2D-Array rechteckig ist

FelixN

Mitglied
Liebe Community,

ich bin gerade leider extrem am verzweifeln.. folgende Aufgabenstellung:

Ich möchte eine Methode - public static boolean isRectangular(int[][] array - erstellen, die mir zurückgibt, ob ein 2D-Array die Eigenschaft eines Rechtecks hat, also jede Zeile die gleiche Anzahl an Spalten hat. Sollte es rechteckig sein, soll das Array mit Kommas getrennt ausgegeben werden, ansonsten soll "false" ausgegeben werden. Meine Überlegung war, dass es ja nur nicht rechteckig sein kann, wenn manche Stellen des Array "null" sind, also nicht belegt sind mit einem Wert. Oder ist das schon ein grober Denkfehler und es geht ganz anders...?

Eigentlich muss man ja nur prüfen, ob jede Zeile die gleiche Länge hat wie die erste Zeile.. aber komme nicht drauf wie man das ausdrückt.. hat jemand einen Tipp?? Wäre super dankbar!

Folgenden Code hab ich mal gebastelt.. aber vermutlich völliger Quatsch.

Grüße und danke!

public class ArrayMethode {

public static boolean isRectangular(int[][] array) {

for (int zeile = 0; zeile < array.length; zeile++) {
for (int spalte = 0; spalte < array[zeile].length; spalte++) {

if (array [spalte] == null || array [zeile] == null) {
System.out.println("false");

} else {
System.out.println(array[zeile][spalte]);
}
}
}
return true;
}

public static void main(String[] args) {
int[][] array = {{20 }, //nur mal um zu prüfen was passiert
{8, 7, 15},
{7, 13, 47}
};

isRectangular(array);

}
}
 
Meine Überlegung war, dass es ja nur nicht rechteckig sein kann, wenn manche Stellen des Array "null" sind, also nicht belegt sind mit einem Wert. Oder ist das schon ein grober Denkfehler und es geht ganz anders...?

Eigentlich muss man ja nur prüfen, ob jede Zeile die gleiche Länge hat wie die erste Zeile.. aber komme nicht drauf wie man das ausdrückt.. hat jemand einen Tipp?? Wäre super dankbar!

Nein, der erste Gedanke ist stimmt nicht. Den kannst Du maximal als Sonderfall betrachten, für den Fall, dass ein tatsächlich einmal null vorkommen sollte. Aber den würde ich erst einmal ignorieren.

Der zweite Gedanke hört sich gut an. Und da kannst Du ja mal deinen Code anschauen. Du hast da zwei verschaltete Schleifen - kannst Du mal beschreiben, was diese verschachtelten Schleifen machen bzw. was da für Werte drin vorkommen?
Da solltest du dann evtl. schon etwas erkennen.

Ansonsten kann man ja auch mal kleiner anfangen: Könntest Du eine Methode schreiben, das für alle Teil-Arrays die Länge ausgibt?
 
Der zweite Gedanke hört sich gut an. Und da kannst Du ja mal deinen Code anschauen. Du hast da zwei verschaltete Schleifen - kannst Du mal beschreiben, was diese verschachtelten Schleifen machen bzw. was da für Werte drin vorkommen?
Da solltest du dann evtl. schon etwas erkennen.

Ok, danke schonmal! Also die beiden for-Schleifen durchlaufen ja mein Array sozusagen an jeder einzelnen Stelle von 0 bis array.length, oder? Sprich die Werte die darin vorkommen, sind eben die übergebenen Werte des Arrays dann später..?

Ich hänge nun daran, dass ich nicht weiss, wie man die Länge einer Zeile prüft. Vllt sowas wie array [zeile] [array.length] ??
 
Die innere Schleife läuft ja durch alle Elemente. Daher muss die Schleife ja wissen, wie viele Elemente das Array hat. Daher findet sich genau in der inneren Schleife das, was mihe7 gesagt hat.
 
okay jetzt komm ich der Spur näher. Meine Idee ist jetzt, zu vergleichen ob

if (array[0].length == array [zeile].length) gegeben ist. Weil sobald ja eine Zeile nicht die Länge hat wie Zeile 0, ist es nicht rechteckig.

aber von der Ausgabe her passt es noch nicht.. es soll nur ausgegeben werden "false" oder eben das ganze Array.

Brauche ich dann hier die beiden For-Schleifen überhaupt?
 
Die Ausgabe sollst Du aber bestimmt (hoffentlich) nicht in der Methode isRectangular machen; die gibt nur zurück, ob das Array rechteckig ist oder nicht.

mh doch schon so wie ich das verstehe! also das hier ist die exakte Aufgabenstellung:

Erstellen Sie eine möglichst effizient eine Methode

public static boolean isRectangular(int[][] array)

die überprüft, ob ein gegebenes zweidimensionales Array “rechteckig” ist, also in jeder Zeile die gleiche
Anzahl an Spalten enthält.
Falls das Array rechteckig ist, geben Sie das Array auf der Standardausgabe aus, wobei jeweils zwei
Zahlen durch ein Komma getrennt sein sollen. Der Rückgabewert der Funktion soll in diesem Fall true
sein. Falls das Array nicht rechteckig ist, soll nur false zurückgegeben werden. Versehen Sie Ihre Lösung mit ausreichend Kommentaren.

das hier ist mein code.. aber er gibt mir eben für jede einzelne Stelle immer den Wert zurück oder eben false, was auch logisch ist. Muss ich hier nochmal eine neue Bedingung wo machen, dass eben Ausgabe nur kommt sobald die gesamte Methode wahr oder falsch ist?

JSX:
public class ArrayMethode {

    public static boolean isRectangular(int[][] array) {

        for (int zeile = 0; zeile < array.length; zeile++) {
            for (int spalte = 0; spalte < array[zeile].length; spalte++) {

                if (array[0].length == array [zeile].length)  {
                    System.out.println(array[spalte][zeile]);

                } else {
                    System.out.println("false");
                }
            }
        }
        return true;
    }

    public static void main(String[] args) {
        int[][] array = {{20 },
                        {8, 7, 15},
                        {7, 13, 47}
        };

        isRectangular(array);

    }
}
 
mh doch schon so wie ich das verstehe! also das hier ist die exakte Aufgabenstellung:
Ja, würde ich auch so verstehen :-(

Aber Du solltest es wie getrennte Anforderungen behandeln. D. h. erst prüfen, ob das Array rechteckig ist und erst danach ggf. ausgeben. D. h. Du hast einmal eine Schleife für die Prüfung und danach nochmal zwei Schleifen für die Ausgabe.
 
Also ich verstehe das eher so, dass sich der zweite Teil dann auf den Code in der main Methode bezieht.

Also dass Du sowas in der Art in main hast:
Java:
if (isRectangular(array)) {
    print(array);
} else {
    System.out.printlne(false);
}

Methoden sollten immer nach dem benannt werden, was sie machen und isRectangular prüft genau das, was die Methode angibt. Und da ist dann keine Ausgabe dabei. Ansonsten wäre die Methode checkRectangularAndPrint oder so ...

Und bei Deinem Code ist einiges im argen. Einfach mal ein ersten wichtigen Punkt:
Ein if/else Konstrukt in einer Schleife, die eine Bedingung für das Gesamte überprüft, ist eigentlich immer falsch. Das kann nur richtig sein, wenn Du für jedes Element etwas machen willst ...

Und deine Frage bezüglich "Brauche ich dann hier die beiden For-Schleifen überhaupt?" Bist Du auf dem richtigen Weg, nur bitte trenn die Prüfung von der Ausgabe!
 
Und bei Deinem Code ist einiges im argen. Einfach mal ein ersten wichtigen Punkt:
Ein if/else Konstrukt in einer Schleife, die eine Bedingung für das Gesamte überprüft, ist eigentlich immer falsch. Das kann nur richtig sein, wenn Du für jedes Element etwas machen willst ...

das eine IF-Anweisung hier nicht passt ist mir nun auch aufgefallen und macht total Sinn, da hast du Recht!

Aber das ich die for-Schleifen nicht brauche, leuchtet mir nicht so richtig ein, ich brauch doch die Bezeichnung für den Inhalt der eckigen Klammern bei der Prüfschleife? Da hab ich mich jetzt mal für die While-Schleife entschieden. Nur passt was mit der Rückgabe nicht so wirklich...

hab jetzt mal das hier gebastelt..

Code:
public static boolean isRectangular(int[][] array) {

        for (int zeile = 0; zeile < array.length; zeile++) {
            for (int spalte = 0; spalte < array[zeile].length; spalte++) {

                while  (array[0].length == array [zeile].length ) {
                    zeile++;
                    spalte++;
                }
return true;

            }
        }
        return false;
    }
 
Also Du hast eine Menge Stifte und willst wissen, ob alle gleich lang sind.

Also: Du prüfst nun, ob diese alle gleich lang sind.
Du prüfst immer einen Stift mit dem ersten Stift. Wann hast Du welches Ergebnis?
Was machst Du, wenn die zwei Stifte gleich lang sind?
Was machst Du, wenn diese nicht gleich lang sind?

Musst Du dann jeden Stift von Anfang bis Ende prüfen, ob die Farbe vom Stift evtl. abgeplatzt ist? Oder für jeden mm der Länger den Durchmesser prüfen? Oder schauen, ob da Druckspuren zu erkennen sind? (Die Frage ist nur: Sind die Stifte gleich lang!)
 
Erstmal vielen Dank für deine Geduld, das ist echt nett! 🙂

Also, ich habe es vom Sinn her verstanden. Nun hangts noch bisschen an der Implementierung.. ich habe folgendes gemacht ->

hab es mit einer While Schleife versucht..

Code:
    public static boolean isRectangular(int[][] array) {

        int zeile = 0;


        while (array[0].length == array[zeile].length) {
            zeile++;
            return true;

        }

        return false;
    }

wo steckt hier mein Fehler.. im Prinzip prüfe ich ja jedes mal "ist die Zeile 0 gleich lang wie Zeile X" -> falls ja erhöhe zeile +1 und return solange "true", bis die Bedingung nicht mehr stimmt, und dann return false.
 
Zuletzt bearbeitet:
Das return verlässt doch sofort die Schleife.

Der Aufbau von so Prüfroutinen ist eigentlich immer gleich:
Gehe alle Elemente durch
- und prüfe ob du abbrechen kannst (mit Ergebnis zurück geben)
Wenn Du durchgekommen bist, dann gab es kein Abbruch Kriterium.

Wenn Du wissen willst, ob alle Stifte gleich lang sein, dann prüfst Du die Stifte, bis Du diese Frage beantworten kannst:
Sobald Du einen Stift gefunden hast, der nicht so lang ist wie der Erste, kannst Du sagen: Die Stifte sind nicht alle gleich lang.
Wenn Du alle Stifte verglichen hast und hast neinen gefunden, der nicht so lang war wie der erste, dann weißt Du, alle Stifte sind gleich lang.

Also hast immer etwas wie

Code:
for/while loop {
  if (someCheck) return false;
}
return true;

Natürlich kann der Returnwert umgedreht sein. (Klar, Wenn die Frage ist: "Sind alle Stifte gleich lang" heißt die Antwort nein. Aber ich kann die Frage ja umdrehen: "Haben die Stifte teilweise unterschiedliche Längen?" - Da kann die Prüfung 1:1 laufen, aber die Antwort bei unterschiedlicher Länge heißt dann jetzt ja und nicht mehr nein.

==> Somit: Super, du hast Dich von den ganzen Schleifen, die zu viel waren, getrennt. So gefällt mir der Code schon deutlich besser. Und wie die Abfrage aussehen muss bekommst Du jetzt vielleicht auch noch richtig hin!
 
okay, also den Sinn was ich erreichen will. habe ich verstanden. In die for/while Schleife noch eine IF-Abfrage einzubauen macht mir auch Sinn. Allerdings hab ich jetzt noch Probleme dabei, die Abfrage richtig zu formulieren.. bei mir gibt er einfach immer true zurück, egal wie das Array aussieht.. frag mich langsam ob ich einfach zu doof bin 🙁

Code:
  public static boolean isRectangular(int[][]array) {


        for (int zeile = 0; array[0].length == array[zeile].length; zeile++) {

            if (array[0].length == array[zeile].length) {
                zeile++;

            } else {
                return false;
            }
        }
        return true;
    }
 
ahhh ich glaub ich mein Fehler evtl. entdeckt! Ich habe mal die Abbruchbedingung in der For-Schleife geändert:

Code:
public class ArrayMethode {



    public static boolean isRectangular(int[][]array) {





        for (int zeile = 0; zeile < array.length; zeile++) {



            if (array[0].length == array[zeile].length) {

                zeile++;



            } else {

                return false;

            }

        }

        return true;

    }

Jetzt scheint es zu funktionieren !! Oder?
 
Ja, fast richtig! Das zeile++ hast Du nun aber doppelt. In der for Schleife zählst Du schon hoch, daher musst Du bei Gleicheheit nichts machen. Also kannst Du das == zu != machen um dann nur das return false stehen zu lassen!
 
sooo, müsste dann so aussehen:

Code:
   public static boolean isRectangular(int[][]array) {


        for (int zeile = 0; zeile < array[zeile].length; zeile++) {

            if (array[0].length != array[zeile].length) {

                return false;
            }
        }
        return true;
    }
 
Ja, das sollte funktionieren.

Jetzt könntest Du noch kurz überlegen, ob man da noch etwas optimieren kann. Wenn die Schleife durchlaufen wird: welche Zeile wird dann mit welcher Zeile geprüft? (Da ist nur eine kleine Optimierung möglich.)
 
Mh meinst du die Prüfung in der for-Schleife von
zeile < array[zeile].length in zeile < array.length geändert werden sollte?
Sonst zählt er ja nur so lange wie die Zeile lang ist, aber soll ja einfach alle vorhandenen Zeilen durchzählen?
 
Wenn Du mich meinst: ja, ich glaube aber eher, dass sich unsere Beiträge überschnitten haben. Wenn Du die Optimierung meinst: wie hoch ist die Wahrscheinlichkeit, dass sich die Länge der ersten Zeile von der Länge der ersten Zeile unterscheidet? 🙂
 
Hallo ihr beiden,

solltet ihr an eurem Wochenende Zeit für einen kurz Blick hier drauf haben..:

Habe nun Rücksprache mit meinem Tutor gehalten und die Ausgabe soll tatsächlich in die isRectangular - Methode mit rein, auch wenn das, wie ich es verstanden habe, nicht der feine Weg ist.

Wie ich das mache hab ich soweit rausbekommen, also die Ausgabe muss vor Abbruch durch "return true" kommen und nach der false-Prüfung, denn es soll nur eine Ausgabe stattfinden, wenn es rechteckig ist, sonst nicht.

Die möchten laut Aufgabenstellung nun zwischen allen Zahlen ein Komma. Nach dem letzten Wert soll natürlich kein Komma stehen, das habe ich jetzt so gelöst. in dem ich jede Stelle mit der letzten Stelle im Array vergleiche. Allerdings klappt das nur, wenn kein Wert innerhalb identisch mit dem letzten Wert ist.. habt ihr vielleicht hier eine Idee?

Code:
    public static boolean isRectangular(int[][]array) {


        for (int zeile = 1; zeile < array.length; zeile++) {

            if (array[0].length != array[zeile].length) {

                return false;
            }
        }

        for (int i = 0; i < array.length; i++) {
            for (int k = 0; k < array[i].length; k++) {

                if (array[i][k] == array[array.length - 1][array[i].length-1]) {
                    System.out.print(array[i][k]);

                } else {
                    System.out.print(array[i][k] + ",");
                }
            }
        }
            return true;
}
 
Also dein IF vergleicht jetzt den Wert des aktuellen Elements mit dem letzten Element des letzten Arrays. Willst Du das?

Sag doch mal in Worten, was Du genau prüfen willst.
 
Also mein Ziel ist es das gesamte Array mit Kommas zwischen den Werten auszugeben, aber nach der letzten Stelle soll natürlich kein Komma sein.

Daher möchte ich eine Anweisung erzeugen, die mir in der Ausgabe hinter jeden Wert ein Komma setzt, außer eben beim letzten.

Das hab ich jetzt so gemacht, in dem ich immer den Wert des aktuellen mit dem letzten vergleiche. Jedoch haut das nicht hin, wenn innerhalb ein Wert vorkommt, der mit dem letzen identisch ist.. aber ich weiss nicht wie ich es sonst lösen kann. Ich brauche einen Ausdruck, der nicht die Werte vergleicht, sondern die Indexstellen an sich.. verstehst du was ich meine? :/
 
Also willst Du nicht den Wert vergleichen. Sondern Du willst wissen, ob die Position die letzte ist.
- also welche Variable speichert die aktuelle Position?
- welchen Wert hat die Variable an der letzten Stelle?
 
Also i ist die äußere Schleife und damit gehst Du sozusagen die Zeilen durch. Daher ist i uninteressant.

Aber mit k gehst Du ja eine einzelne Zeile durch. Und du musst ja nur schauen, was der letzte Wert der Schleife ist. Die Bedingung in der Schleife ist array[i].length und da der Wert kleines sein soll und du immer um 1 hochzählst, ist der letzte Wert, der noch durchlaufen wird welcher?
 
ok stimmt, dann würde die Prüfung ja so aussehen -> if ( k == array.length -1 ) , dann print ohne Komma, ansonsten mit.

Code:
 for (int i = 0; i < array.length; i++) {
            for (int k = 0; k < array[i].length; k++) {

                if (k == array.length -1 ) {
                    System.out.print(array[i][k]);
                } else {
                    System.out.print(array[i][k] + ",");
                }
            }
        }

er druckt es bei einem Beispiel aber immernoch falsch... tut mir echt leid falls ich nerve 🙁 Aber das macht mich langsam fertig
 
Du musst ermitteln, um das wie vielte Element es sich handelt. Das ist nicht einfach k, denn k wird bei jeder nächsten Iteration der äußeren Schleife wieder auf 0 zurückgesetzt.
 
ok, das heisst also wenn Durchlauf Zeile 0 abgeschlossen ist, dann wird mein k wieder zu null?

Aber wie ist dann der Ausdruck für die letzte Position der letzten Zeile.. ? Aus keinem unserer Skripte oder auch sonst find ich echt keine Antwort. Dreh langsam durch
 
ok, das heisst also wenn Durchlauf Zeile 0 abgeschlossen ist, dann wird mein k wieder zu null?
Fast, wenn der Durchlauf von Zeile 1 beginnt, wird ja die innere for-Schleife ausgeführt und da wird Dein k wieder zu 0.

Java:
for (int i = 0; i < x; i++) {
    doSomething();
}
ist äquivalent zu
Code:
int i = 0; 
while (i < x) {
    doSomething();
    i++;
}

Wenn Du das nun in einer weitere for-Schleife packst:
Java:
for (int k = 0; k < y; k++) {
    int i = 0; 
    while (i < x) {
        doSomething();
        i++;
    }
}
wird es recht deutlich, dass das i bei jeder Iteration auf 0 zurückgesetzt wird.

Aber wie ist dann der Ausdruck für die letzte Position der letzten Zeile.. ?
Naja, Du hast ein rechteckiges Array, d. h. jede Zeile hat gleich viele Spalten:
Code:
i
0 | a b c
1 | d e f
2 | g h i
Ist das i == 1, hast Du also bereits array[1].length Elemente in der darüber liegenden Zeile verarbeitet. Dazu kommt noch k für das Element in der aktuellen Zeile. Beim f ist k == 2, also hat f demnach de "Gesamtindex" 3+2 = 5.

Ist das i == 2, hast Du also bereits 2 * array[2].length Elemente in den darüber liegenden Zeilen verarbeitet.

Allgemein hast Du also i * array[i].length Elemente in den darüber liegenden Zeilen verarbeitet. Das k musst Du dann noch addieren.
 
ok, danke für die ausführliche und gute Erklärung, das versteh ich jetzt.

Sprich meine letzte Position ist i * array.length + k.

Und mit was vergleiche ich das jetzt in der Abfrage? weil wenn ich das so vergleiche

Code:
 if (i * array[i].length + k == array.length -1) {
                    System.out.print(array[i][k]);
                } else {
                    System.out.print(array[i][k] + ",");

gehts nicht.

Muss die Aufgabe morgen abgeben und steh super aufm Schlauch und mein Kopf ist Matsch, hatte den ganzen Tag Uni... aber kann es trotzdem verstehen wenn deine Geduld am Ende ist ^^ !
 
yeeeees! ich danke dir recht herzlich, du bist klasse!

hab gerade auch von einem Kommilitone die Lösung bekommen, die letztes Semester in der Musterlösung stande..

Code:
// Alles ist glatt gelaufen, gib die Matrix aus
16 for (int line = 0; line < array.length; line++) {
17 for (int column = 0; column < array[line].length; column++) {
5
18 System.out.print(array[line][column]
19 + (column != array[line].length - 1 ? ", " : "\n"));
20 }
21 }
22
23

die funzt bei mir nichtmal irgendwie, aber ist auch völlig egal, unsere Lösung funktioniert wunderbar. Nochmals danke!! 🙂
 
ja aber in der Aufgabenstellung steht nur:
Falls das Array rechteckig ist, geben Sie das Array auf der Standardausgabe aus, wobei jeweils zwei
Zahlen durch ein Komma getrennt sein sollen.
 
OK, das kann man so oder so interpretieren, da hätte ich mich für die einfachere Variante entschieden, zumal eh schon immer von "rechteckig" die Rede ist 🙂
 
Die leichtere ist die, die Zeilen untereinander auszugeben (eben rechteckig), weil Du dann nicht mit einem Gesamtindex rumzurechnen brauchst.

Das enspricht dann dem Code, den Du schon hattest, nur dass Du im Fall des "Endes einer Array-Zeile" statt einem Komma ein Newline ausgibst.
Java:
for (int i = 0; i < arr.length; i++) {
    for (int k = 0; k < arr[i].length; k++) {
        if (k == arr[i].length - 1) {
            System.out.print(arr[i][k] + "\n");
        } else {
            System.out.print(arr[i][k] + ", ");
        }
    }
}

Für rechteckige Arrays, die wenigstens eine Zahl enthalten, geht es z. B. auch ohne Fallunterscheidung innerhalb der Schleife:
Java:
for (int i = 0; i < arr.length; i++) {
    System.out.print(arr[i][0]);
    for (int k = 1; k < arr[i].length; k++) {        
        System.out.print(", " + arr[i][k]);
    }
    System.out.println();
}
 

Zurück
Oben