Clonando matrizes multidimensionais

8

Eu quero clonar uma matriz multidimensional @a em uma matriz @b.

Eu procedi da maneira mais intuitiva e criei o seguinte:

    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;

e a impressão é:

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

Isso significa que as duas matrizes @a e @b estão ligadas?

Questões:

  1. Por que o array @a está vinculado ao array @b (qual é o objetivo do método clone nessa situação? Sabemos que o clone se comporta como pretendido para matrizes unidimensionais)
  2. Como posso realmente clonar @a a @b (multidimensional)?
  3. Qual é a maneira mais eficiente (tempo limitado) de fazer isso?
jakar
fonte

Respostas:

10

O que você tem não é uma matriz multidimensional, mas uma matriz de matrizes. Como cloneé raso, ele apenas copiará a matriz de nível superior. Nesse caso, o clonetambém é redundante, pois a atribuição em uma matriz já é uma operação de cópia.

Uma correção simples é clonar cada uma das matrizes aninhadas:

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

Como alternativa, você pode usar uma matriz multidimensional real. A declaração ficaria assim:

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

E então a cópia para outra matriz seria:

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

As atribuições também precisam ser atualizadas para usar a sintaxe multidimensional:

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

E, finalmente, o resultado disso:

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

É como desejado:

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

Como limpeza final, você também pode "derramar" uma sequência conceitualmente infinita de 0s na matriz para inicializá-la:

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

O que significa que a estrutura 3x3 não precisa ser replicada à direita.

Jonathan Worthington
fonte
ESTÁ BEM. Entendi. Então, quando tento alterar @a [0] [1], na realidade, altero o Scalar @a [0] (que é uma matriz), nesse caso o segundo valor da matriz. E quando altero @b [1] [0], na realidade, altero o conteúdo escalar de @b [1]. E como o método clone faz uma cópia superficial da matriz @a, as matrizes @a e @b têm como conteúdo os mesmos 3 escalares que são matrizes. É por isso que obtenho o mesmo resultado quando imprimo as duas matrizes no final! Isso está correto?
Jakar
2
@ikarpenis @Larry usa escalar (letras minúsculas 's') no sentido da wikipedia e Scalar(letras maiúsculas 'S') para significar o padrão de Raku construído em contêiner escalar . A Scalarnunca é uma matriz; mas pode conter (uma referência a) um Array. Uma atribuição @a[0][1] = ...não altera o escalar ou Scalar @a[0]e também não coloca um novo Arrayno Scalarcontêiner @a[0]. Apenas altera o valor mantido no 2º Scalarno existente Arrayretido no Scalarlimite existente para @a[0].
raiph
5

@ae @bnão estão vinculados . Eles apenas contêm as mesmas coisas. O clonenão recurva e apenas clona a matriz externa.

Uma maneira de conseguir o que você quer seria

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