gpt4 book ai didi

arrays - 为什么 Bash 关联数组不保持索引顺序?

转载 作者:行者123 更新时间:2023-12-02 07:03:22 25 4
gpt4 key购买 nike

我正在创建关联数组以在 for 循环中进行处理,但我在索引顺序中得到了一些奇怪的结果。请看一下这个示例脚本:

#!/bin/bash
declare -A test1=(
[d]=1w45
[e]=2dfg
[m]=3df
[o]=4df
)

declare -A test2=(
[d1]=1w45
[e2]=2dfg
[m3]=3df
[o4]=4df
)

declare -A test3=(
[1d]=1w45
[2e]=2dfg
[3m]=3df
[4o]=4df
)

echo ${!test1[@]}
echo ${!test2[@]}
echo ${!test3[@]}

输出将是

$ ./test 
d e m o
o4 m3 e2 d1
3m 4o 1d 2e

为什么项目的顺序会改变?以及如何绕过这种行为?提前致谢!

最佳答案

Why don't bash associative arrays maintain index order?

因为它们的设计目的不是这样做。

Why order of items is changing?

bash associative array implementation使用hash library并存储索引的哈希值。这些哈希值存储在buckets中与 128 default number of buckets 。哈希值是用函数 hash_string() 计算的使用简单的乘法和按位异或。关联数组的键列出 in the order buckets appearBucket number is calculated key的哈希值与桶数按位与运算减1。

我编译了bash commit 6c6454cb18d7cd30b3b26d5ba6479431e599f3ed对我来说你的脚本输出:

$ ./test 
o m e d
d1 e2 m3 o4
1d 3m 2e 4o

因此,我复制了 hash_string() 函数并编写了一个小型 C 程序,该程序将输出键的存储桶编号并编译和执行:

#include <stdio.h>

#define FNV_OFFSET 2166136261
#define FNV_PRIME 16777619

unsigned int
hash_string (s)
const char *s;
{
register unsigned int i;

for (i = FNV_OFFSET; *s; s++)
{
i *= FNV_PRIME;
i ^= *s;
}

return i;
}

int main() {
const char *s[] = {
"o", "m", "e", "d",
"d1", "e2", "m3", "o4",
"1d", "3m", "2e", "4",
};
for (int i = 0; i < sizeof(s)/sizeof(*s); ++i) {
printf("%3s %3d\n",
s[i],
hash_string(s[i]) & (128 - 1));
}
}

程序输出两列,键和键的桶号(添加了额外的空行):

  o 112
m 114
e 122
d 123

d1 16
e2 60
m3 69
o4 100

1d 14
3m 41
2e 50
4o 94

输出的键的顺序是根据它们所在的哈希表中的桶的顺序进行排序的,因此它们按照该顺序输出。这就是项目顺序发生变化的原因。

也就是说,您不应该依赖这种行为,因为如果 bash 的作者决定更改哈希函数或进行任何其他更改,则键的输出顺序可能会更改。

And how to bypass this behavior?

没有办法绕过这个。 Bash 数组使用哈希表来存储哈希值。键的插入顺序不存储在任何地方。

当然,您可以通过修补 bash 来绕过此行为,以实现您请求的此类功能。

也就是说,我只会使用两个数组:

keys=(d1 e2 m3 o4)
elements=(1w45 2dfg 3df 4df)
declare -A test2
for ((i=0;i<${#keys[@]};++i)); do
test2[${keys[$i]}]="${elements[$i]}"
done
# or maybe something along:
declare -A test2=($(paste -zd <(printf "[%s]=\0" "${keys[@]}") <(printf "%q \0" "${elements[@]}"))

这样,您就可以按照将键插入到单独的 keys 数组中的顺序对其进行迭代。

关于arrays - 为什么 Bash 关联数组不保持索引顺序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60396504/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com