Klonen mehrdimensionaler Arrays

8

Ich möchte ein mehrdimensionales Array @ain ein Array klonen @b.

Ich habe den intuitivsten Weg eingeschlagen und mir Folgendes ausgedacht:

    my @a = [0, 0, 0], [0, 0, 0], [0, 0, 0];

    my @b = @a.clone;

    @a[0][1] = 1;
    @b[1][0] = 1;

    say '@a : ' ~ @a.gist;
    say '@b : ' ~ @b.gist;

und der Ausdruck ist:

    @a : [[0 1 0] [1 0 0] [0 0 0]]
    @b : [[0 1 0] [1 0 0] [0 0 0]]

Das heißt, dass die beiden Arrays @a und @b gebunden sind?

Fragen:

  1. Warum Array @a an Array @b gebunden ist (Was ist der Zweck der Klonmethode in dieser Situation? Wir wissen, dass sich Klone so verhalten, wie es für eindimensionale Arrays beabsichtigt ist).
  2. Wie kann ich @a wirklich zu @b klonen (mehrdimensional)?
  3. Welches ist der effizienteste (zeitlich begrenzte) Weg, dies zu tun?
Jakar
quelle

Antworten:

10

Was Sie haben, ist kein mehrdimensionales Array, sondern ein Array von Arrays. Da clonees flach ist, wird nur das Array der obersten Ebene kopiert. In diesem Fall ist das cloneauch redundant, da die Zuordnung zu einem Array bereits ein Kopiervorgang ist.

Eine einfache Lösung besteht darin, jedes der verschachtelten Arrays zu klonen:

my @b = @a.map(*.clone);

Alternativ können Sie ein echtes mehrdimensionales Array verwenden. Die Erklärung würde folgendermaßen aussehen:

my @a[3;3] = [0, 0, 0], [0, 0, 0], [0, 0, 0];

Und dann wäre das Kopieren in ein anderes Array:

my @b[3;3] = @a;

Die Zuweisungen müssen auch aktualisiert werden, um die mehrdimensionale Syntax zu verwenden:

@a[0;1] = 1;
@b[1;0] = 1;

Und schließlich das Ergebnis davon:

say '@a : ' ~ @a.gist;
say '@b : ' ~ @b.gist;

Ist wie gewünscht:

@a : [[0 1 0] [0 0 0] [0 0 0]]
@b : [[0 0 0] [1 0 0] [0 0 0]]

Als letzte Bereinigung können Sie auch eine konzeptionell unendliche Folge von 0s in das Array "gießen" , um es zu initialisieren:

my @a[3;3] Z= 0 xx *;

Dies bedeutet, dass die 3x3-Struktur nicht rechts repliziert werden muss.

Jonathan Worthington
quelle
OK. Ich habs. Wenn ich also versuche, @a [0] [1] zu ändern, ändere ich in Wirklichkeit den Skalar @a [0] (der ein Array ist), in diesem Fall den zweiten Wert des Arrays. Und wenn ich in Wirklichkeit @b [1] [0] ändere, ändere ich den Skalargehalt von @b [1]. Und da die Klonmethode eine flache Kopie des Arrays @a erstellt, haben beide Arrays @a und @b als Inhalt dieselben 3 Skalare, die Arrays sind. Deshalb bekomme ich das gleiche Ergebnis, wenn ich die beiden Arrays am Ende ausdrucke! Ist das korrekt?
Jakar
2
@ikarpenis @Larry Verwendung Skalar (Klein ‚s‘) in der wikipedia Sinn und Scalar(Groß- ‚S‘) bedeuten Raku Standard in skalare eingebauten Behälter . A Scalarist niemals ein Array; aber es kann enthalten (ein Hinweis auf) ein Array. Eine Zuweisung @a[0][1] = ...ändert weder den Skalar noch Scalar @a[0]und legt auch keine neue Arrayin den ScalarContainer @a[0]. Es ändert nur den Wert, der im 2. Scalarin dem vorhandenen Wert Arrayin der vorhandenen ScalarBindung an gehalten wird @a[0].
Raiph
5

@aund @bsind nicht gebunden . Sie enthalten einfach die gleichen Dinge. Das clonerekursiert nicht und klont nur das äußere Array.

Ein Weg, um das zu erreichen, was Sie wollen, wäre

@b = @a.map: *.clone; 
Holli
quelle