如果我有一个字符串数组并且我想更改一个值中的单个字符,我可以这样做:
$ 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
另请注意,在每种情况下处理数组都比处理标量慢。