为什么Bash关联数组不维护索引顺序? [英] Why don't Bash associative arrays maintain index order?

查看:95
本文介绍了为什么Bash关联数组不维护索引顺序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm creating associative arrays to process in a for loop but i'm getting some strange results in index order. Please take a look at this example script:

#!/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 is the order of items changing? And how to bypass this behavior? Thanks in advance!

推荐答案

为什么bash关联数组不维护索引顺序?

Why don't bash associative arrays maintain index order?

因为他们被设计为不这样做.

Because they are designed not to do this.

为什么商品的顺序在改变?

Why order of items is changing?

Bash 关联数组实现使用哈希库,并存储索引哈希.这些哈希存储在存储桶中,其中包含128个默认存储桶数量.使用函数 hash_string() 计算散列简单乘法和按位XOR.关联数组的键在存储桶出现的顺序中列出. 通过散列之间的按位AND运算来计算桶号密钥的值和存储桶数减少了1.

Bash associative array implementation uses a hash library and stores hashes of indexes. These hashes are stored in buckets with 128 default number of buckets. The hash is calculated with the function hash_string() using a simple multiplication and a bitwise XOR. The keys of the associative array are listed in the order buckets appear. Bucket number is calculated by a bitwise AND operation between the hash value of the key and the number of buckets decreased by 1.

我编译了 bash提交6c6454cb18d7cd30b3b26d5ba6479431e599f3ed 并为输出: >

I compiled bash commit 6c6454cb18d7cd30b3b26d5ba6479431e599f3ed and for me your script outputs:

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

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

So I copied the hash_string() function and written a small C program that would output the bucket number of the keys and compiled and executed:

#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));
    }
}

程序输出两列,密钥和密钥的存储区编号(添加了额外的空行):

The program outputs two columns, the key and the bucket number of the key (added extra empty lines):

  o 112
  m 114
  e 122
  d 123

 d1  16
 e2  60
 m3  69
 o4 100

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

输出键的顺序是根据它们在哈希表中的存储桶的顺序进行排序的,因此它们按该顺序输出.这就是更改项目顺序的原因.

The order of keys outputted is sorted using the order of buckets in the hash table they are into, so they are outputted in that order. This is why the order of items changed.

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

That said, you should not rely on this behaviour, as the output order of keys can change if the author of bash decides to change the hashing function or make any other change.

以及如何绕过这种行为?

And how to bypass this behavior?

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

There is no way to bypass this. Bash arrays use hash table to store the hashes. The insertion order of keys is not stored anywhere.

当然,您可以通过修补bash来实现所需的功能来绕过此行为.

Of course, you can bypass this behaviour by patching bash to implement such functionality that you request.

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

That said, I would just use two arrays:

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数组中的顺序来遍历键.

That way you can iterate over keys in the order you inserted them in a separate keys array.

这篇关于为什么Bash关联数组不维护索引顺序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆