Bash.Итерация ассоциативного массива (упорядоченная и без дубликатов) - PullRequest
0 голосов
/ 12 декабря 2018

У меня две проблемы при работе с ассоциативными массивами.Во-первых, я не могу сохранить собственный заказ.

#!/bin/bash

#First part, I just want to print it ordered in the custom created order (non-alphabetical)
declare -gA array
array["PREFIX_THIS","value"]="true"
array["PREFIX_IS","value"]="false"
array["PREFIX_AN","value"]="true"
array["PREFIX_ORDERED","value"]="true"
array["PREFIX_ARRAY","value"]="true"

for item in "${!array[@]}"; do
    echo "${item}"
done

Желаемый вывод:

PREFIX_THIS,value
PREFIX_IS,value
PREFIX_AN,value
PREFIX_ORDERED,value
PREFIX_ARRAY,value

Но я получаю это:

PREFIX_IS,value
PREFIX_ORDERED,value
PREFIX_THIS,value
PREFIX_AN,value
PREFIX_ARRAY,value

Пока здесь первая проблема.Для второй проблемы порядок не важен.Я добавил больше материала в ассоциативный массив, и я просто хочу зациклить его без дубликатов.Добавим:

array["PREFIX_THIS","text"]="Text for the var"
array["PREFIX_IS","text"]="Another text"
array["PREFIX_AN","text"]="Text doesn't really matter"
array["PREFIX_ORDERED","text"]="Whatever"
array["PREFIX_ARRAY","text"]="More text"

Я просто хочу зациклить «PREFIX_THIS», «PREFIX_IS», «PREFIX_AN» и т. Д., Печатая каждый из них только один раз.Я просто хочу напечатать, выполняя «эхо» в цикле (порядок для этой части не важен, просто печатать каждый из них только один раз)Желаемый результат:

PREFIX_ORDERED
PREFIX_AN
PREFIX_ARRAY
PREFIX_IS
PREFIX_THIS

Я добился этого, делая "грязные" вещи.Но должен быть более элегантный способ.Это мой рабочий, но не слишком элегантный подход:

already_set=""
var_name=""
for item in "${!array[@]}"; do
    var_name="${item%,*}"
    if [[ ! ${already_set} =~ "${var_name}" ]]; then
        echo "${var_name}"
        already_set+="${item}"
    fi
done

Любая помощь?Спасибо.

1 Ответ

0 голосов
/ 12 декабря 2018

Порядок итераций

Как указал Иньян в комментариях, вы не можете исправить порядок, в котором "${!array[@]}" расширяется для ассоциативных массивов.Однако вы можете хранить все ключи внутри обычного массива, который можно заказать вручную.

keysInCustomOrder=(PREFIX_{THIS,IS,AN,ORDERED,ARRAY})
for key in "${keysInCustomOrder[@]}"; do
    echo "do something with ${array[$key,value]}"
done

Уникальные префиксы ключей

Для вашей второй проблемы: a["key1","key2"] совпадает с a["key1,key2"].В bash массивы всегда 1D, поэтому идеального решения не существует.Однако вы можете использовать следующую однострочную строку, если , никогда не является частью key1.

$ declare -A array=([a,1]=x [a,2]=y [b,1]=z [c,1]=u [c,2]=v)
$ printf %s\\n "${!array[@]}" | cut -d, -f1 | sort -u
a
b
c

Если ваши ключи также могут содержать разрывы строк, удаляйте каждый ключ с нуля \0.

printf %s\\0 "${!array[@]}" | cut -zd, -f1 | sort -zu

В качестве альтернативы вы можете использовать ссылочные переменные для имитации 2D-массивов, однако я бы посоветовал не использовать их.

...