Atribuindo um novo valor diretamente a um índice de caractere de um valor em uma matriz com zsh

5

Se eu tiver uma matriz de strings e quiser alterar um único caractere em um valor, posso fazer isso:

$ array=(hello world)
$ array[2]=${array[2]:0:2}X${array[2]:3}
$ echo $array[2]
woXld

Embora essa solução funcione, ela é lenta para strings muito longas, pois ela reatribui o valor no índice e precisa expandir ambos os lados do valor original, antes e depois do caractere alterado.

Embora seja possível endereçar os índices de caracteres de valores individuais em uma matriz:

$ echo ${array[2][3]}
X

e para atribuir um novo valor a um índice de caracteres para uma variável escalar:

$ string='hello world'
$ string[9]=X
$ echo $string
hello woXld

uma sintaxe semelhante não funciona para matrizes:

$ array[2][3]=X
zsh: no matches found: array[2][3]=X

Existe uma maneira de fazer o que eu quero mais rápido do que com o primeiro método?

    
por sh473 11.03.2017 / 23:32

1 resposta

2

Não parece ser uma maneira de fazer isso com elegância. Isso é provavelmente porque zsh não suporta realmente matrizes aninhadas e, portanto, a sintaxe não está totalmente desenvolvida.

Uma coisa que você pode tentar é usar uma variável temporária em vez de cortar o caractere que deseja alterar:

array=(hello world)
tmp=$array[2]
tmp[3]=X
array[2]=$tmp

Se é realmente mais rápido parece depender do comprimento de $tmp ou possivelmente da matriz como um todo.

Eu fiz um pouco de testes de desempenho e obtive alguns resultados interessantes: Se você está manipulando somente escalares, então substituindo um único charcter por index (método A )

foo[500]=X

parece ser sempre muito mais rápido do que cortar as partições esquerda e direita e construir uma nova string (método B )

foo=${foo:0:499}X${foo:500}

Eu coloco ambos dentro de um loop com 100.000 iterações para strings de 100, 1.000, 10.000 e 100.000 com os seguintes resultados:

./scalar_A100.zsh 100000:         0.16s
./scalar_A1000.zsh 100000:        0.29s
./scalar_A10000.zsh 100000:       1.66s
./scalar_A100000.zsh 100000:     14.63s

 ./scalar_B100.zsh 100000:        0.42s
 ./scalar_B1000.zsh 100000:       1.17s
 ./scalar_B10000.zsh 100000:      5.39s
 ./scalar_B100000.zsh 100000:    46.23s

Infelizmente, quando a string está dentro de uma matriz, ela depende do comprimento da string (ou talvez da própria matriz).

Para o teste de matriz, usei uma matriz com dois elementos, sendo o primeiro "olá" e o segundo novamente uma cadeia com comprimentos entre 100 e 100.000 caracteres.

Exceto para strings curtas parentes, método A (via variável temporária)

foo=$bar[2]
foo[500]=O
bar[2]=$foo

é realmente mais lento do que substituir o elemento da matriz no local por fatias:

bar[2]=${bar[2]:0:499}O${bar[2]:500}

Isso se deve aos valores que estão sendo copiados na variável temporária e de volta ao array. Aqui estão os resultados para isso:

./array_A100.zsh 100000:      0.46s
./array_A1000.zsh 100000:     1.84s
./array_A10000.zsh 100000:   10.50s
./array_A100000.zsh 100000: 101.03s

./array_B100.zsh 100000:      0.60s
./array_B1000.zsh 100000:     1.35s
./array_B10000.zsh 100000:    3.17s
./array_B100000.zsh 100000:  22.13s

Observe também que o tratamento de matrizes é mais lento que os escalares em todos os casos.

    
por 06.04.2017 / 15:17