0

Как сохранить порядок ассоциативного массива?

12

Я пытаюсь итерироваться по ассоциативному массиву в Bash.

Сначала это кажется простым, но цикл не сохраняет исходный порядок элементов массива.

Вот простой скрипт для тестирования:

#!/bin/bash

echo -e "Рабочее окружение\n----------";
lsb_release -a

echo -e "\nВерсия Bash\n----------";
echo -e $BASH_VERSION."\n";

declare -A groups;
groups["group1"]="123";
groups["group2"]="456";
groups["group3"]="789";
groups["group4"]="abc";
groups["group5"]="def";

echo -e "Результат\n----------";
for i in "${!groups[@]}"
do
    echo "$i => ${groups[$i]}";
done

Выходные данные:

Рабочее окружение
----------
Нет доступных модулей LSB.
Идентификатор дистрибутива: Ubuntu
Описание:    Ubuntu 14.04.2 LTS
Версия:    14.04
Кодовое имя:   trusty

Версия Bash
----------
4.3.11(1)-release.

Результат
----------
group3 => 789
group2 => 456
group1 => 123
group5 => def
group4 => abc

Почему я не получаю group1, group2 и т.д. в порядке их объявления?

Я не хочу, чтобы порядок был алфавитным, мне просто нужно, чтобы цикл следовал тому порядку, в котором я объявил элементы массива...

Существует ли способ это сделать?

3 ответ(ов)

0

Ваш подход выглядит вполне разумным. Вы создаете отсортированный массив ключей в словаре, а затем проходите по этому массиву и выводите каждый ключ со значением. Вот пример кода, который может вам помочь:

keys=( $( echo ${!dict[@]} | tr ' ' $'\n' | sort ) )
for k in ${keys[@]}; do
    echo "$k=${dict[$k]}"
done

Здесь вы используете команду echo ${!dict[@]} для получения всех ключей из ассоциативного массива dict, затем преобразуете их в строки с помощью tr, и сортируете с помощью команды sort. Это позволяет вам получить отсортированный список ключей. В цикле for вы просто выводите ключи и соответствующие им значения.

Обратите внимание, что если у вас большой словарь, то регулярное использование команд вроде echo и sort может быть не самым эффективным с точки зрения производительности, но для небольших массивов такой способ вполне приемлем.

0

Еще один способ сортировки элементов в ассоциативном массиве — это сохранять список групп по мере добавления их в массив. Назовите этот элемент с ключом "group_list". Каждый раз, добавляя новую группу, добавляйте её в поле group_list, вставляя пробел для разделения последующих добавлений. Вот пример, который я использовал для своего ассоциативного массива, названного master_array:

master_array["group_list"]+="${new_group} ";

Чтобы пройтись по группам в порядке их добавления, вы можете перебрать поле group_list в for цикле и затем получить доступ к полям групп в ассоциативном массиве. Вот пример кода, который я написал для master_array:

for group in ${master_array["group_list"]}; do
    echo "${group}";
    echo "${master_array[${group},destination_directory]}";
done

А вот вывод этого кода:

"linux"
"${HOME}/Backup/home4"
"data"
"${HOME}/Backup/home4/data"
"pictures"
"${HOME}/Backup/home4/pictures"
"pictures-archive"
"${HOME}/Backup/home4/pictures-archive"
"music"
"${HOME}/Backup/home4/music"

Это похоже на предложение Джонатана Леффлера, но данные хранятся вместе с ассоциативным массивом, не требуется поддерживать два отдельных несвязанных массива. Как видите, порядок не случайный и не алфавитный, а именно тот, в котором я добавлял элементы в массив.

Кроме того, если у вас есть подгруппы, вы можете создать списки подгрупп для каждой группы и пройтись по ним. Именно поэтому я осуществил это так, чтобы избежать необходимости в множественных массивах для доступа к ассоциативному массиву и одновременно позволить расширять группы без необходимости модифицировать код.

0

В приведенном коде представлены несколько удобных абстракций на Bash, которые позволяют работать с ассоциативными массивами и сохранять порядок добавления элементов. Вот разбор функций:

  1. Функция add(): Эта функция используется для добавления пар ключ-значение в ассоциативный массив и одновременного сохранения порядка вставки. Она принимает три аргумента: имя переменной, ключ и значение. Внутри функции создаются глобальные ассоциативный массив и массив для порядка:

    add() {
      local var=$1
      local key=$2
      local val=$3
      declare -ga "${var}_ORDER" # Массив для хранения порядка
      declare -gA "${var}_MAP"    # Ассоциативный массив для хранения значений
      local -n map=${var}_MAP     # Является ссылкой на ассоциативный массив
      local -n order=${var}_ORDER  # Является ссылкой на массив порядка
      order+=("$key")             # Добавляем ключ в массив порядка
      map["$key"]=$val            # Сохраняем значение по ключу
    }
    
  2. Функция get(): Эта функция возвращает значение по заданному ключу из ассоциативного массива.

    get() {
      local var=$1
      local key=$2
      local -n tmp=${var}_MAP  # Используем ссылку на ассоциативный массив
      echo "${tmp[$key]}"      # Возвращаем значение по ключу
    }
    
  3. Функция keys(): Функция выводит все ключи, которые были добавлены в порядок.

    keys() {
      local var=$1
      local -n tmp=${var}_ORDER
      echo "${tmp[@]}"         # Выводим все ключи
    }
    
  4. Функция values(): Возвращает все значения в порядке их добавления.

    values() {
      local var=$1
      local -n map=${var}_MAP
      local -n order=${var}_ORDER
      for k in "${order[@]}"; do
        echo -n "${map[$k]} "  # Выводим значение по каждому ключу
      done
      echo
    }
    
  5. Цикл для вывода всех пар ключ => значение:

    for i in $(keys groups); do
      echo "$i => $(get groups "$i")" # Выводим ключ и соответствующее ему значение
    done
    

Таким образом, этот набор функций позволяет удобно управлять данными в структурированном виде, сохраняя при этом их порядок. Вы можете добавлять, получать, и перечислять как ключи, так и значения, что делает код более удобочитаемым и поддерживаемым.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь