使用 zsh 将新值直接分配到数组中值的字符索引中

使用 zsh 将新值直接分配到数组中值的字符索引中

如果我有一个字符串数组并且我想更改一个值中的单个字符,我可以这样做:

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

尽管此解决方案有效,但对于很长的字符串来说速度很慢,因为它实际上重新分配了索引处的值,并且必须在更改的字符之前和之后扩展原始值的两侧。

虽然可以寻址数组中各个值的字符索引:

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

并将新值分配给标量变量的字符索引:

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

类似的语法不适用于数组:

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

有没有一种方法可以比第一种方法更快地完成我想要的事情?

答案1

似乎没有一种方法可以优雅地做到这一点。这可能是因为zsh实际上并不支持嵌套数组,因此语法尚未完全开发。

您可以尝试的一件事是使用临时变量,而不是围绕要更改的字符进行切片:

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

它实际上是否更快似乎取决于数组的长度$tmp或可能取决于整个数组。

我做了一些性能测试并得到了一些有趣的结果:如果您仅处理标量,则通过索引替换单个字符(方法A

foo[500]=X

似乎总是比切片左右分区并构建新字符串要快得多(方法

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

我将两者放入一个循环中,对长度为 100、1,000、10,000 和 100,000 的字符串进行 100,000 次迭代,结果如下:

./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

不幸的是,当字符串位于数组内部时,它取决于字符串的长度(或者可能是数组本身)。

对于数组测试,我使用了一个包含两个元素的数组,第一个元素是“hello”,第二个元素又是长度在 100 到 100,000 个字符之间的字符串。

除了相对较短的字符串之外,方法A(通过临时变量)

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

实际上比用切片替换数组元素要慢:

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

这是因为值实际上被复制到临时变量中并返回到数组中。以下是结果:

./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

另请注意,在每种情况下处理数组都比处理标量慢。

相关内容