Ordenado por inserção Mapa no bash

3

Existe um mapa ordenado (por inserção) no bash?

Eu sei que há uma estrutura de dados matriz associativa no bash , mas quando iterar sobre ele, a ordem dos elementos não é por inserção. Exemplo abaixo.

Gostaria de manter o mapa ordenado por inserção.

Matriz associativa que não preserva a ordem de veiculação:

declare -A REPLACE_MAP
REPLACE_MAP['b']='2'
REPLACE_MAP['a']='1'
for key in "${!REPLACE_MAP[@]}"; do
    echo "$key - ${REPLACE_MAP["$key"]}"
    value=${REPLACE_MAP["$key"]}
done

Resultado:

a - 1
b - 2

Gostaria que uma estrutura de dados gerasse o seguinte resultado:

b - 2
a - 1
    
por AlikElzin-kilaka 18.07.2016 / 09:37

1 resposta

5

Como Michael Vehrs disse, os arrays associativos de bash fazem não preservar a ordem de inserção. Este é um "recurso" de matrizes associativas em geral . A "mágica" para isso no bash acontece em hashlib.c .

O Bash tem matrizes indexadas , que você pode usar como indicador para o pedido de veiculação:

declare -A REPLACE_MAP
declare -a REPLACE_MAP_INDEX
REPLACE_MAP['b']='2'
REPLACE_MAP_INDEX+=('b')
REPLACE_MAP['a']='1'
REPLACE_MAP_INDEX+=('a')
for key in "${REPLACE_MAP_INDEX[@]}"; do
    printf "%s - %s\n" "$key" "${REPLACE_MAP["$key"]}"
    value=${REPLACE_MAP["$key"]}
done

Outra opção, dependendo dos seus dados, é uma única matriz indexada cujos valores são a chave original e o valor combinado de alguma forma (aqui, usando um espaço):

unset arr
declare -a arr
arr+=("b 2")
arr+=("a 1")
for ckey in "${arr[@]}"; do
  key=${ckey% *}
  value=${ckey#* }
  printf "%s - %s\n" "$key" "$value"
done

... mas se o espaço for uma parte válida de uma chave ou um valor, escolha outra coisa que não seja usada, como um símbolo de pipe, por exemplo:

unset arr
declare -a arr
arr+=("b|2")
arr+=("a|1")
for ckey in "${arr[@]}"; do
  key=${ckey%|*}
  value=${ckey#*|}
  printf "%s - %s\n" "$key" "$value"
done
    
por 18.07.2016 / 18:28