带键值对的for循环,键是不保持排序顺序

带键值对的for循环,键是不保持排序顺序

我有下面的脚本,我注意到这种情况下的 for 循环是按照我指定的顺序执行的,即。预计 2018,2019,2020,但结果为 2019,2018,2020。

在 shell 脚本中是否有特定的原因,是否有任何方法可以保留顺序。

#!/bin/sh

declare -A arr
arr=( ["2018"]=5%12 ["2019"]=1%12 ["2020"]=1%2 )
INPUT_MONTH=$2
INPUT_YEAR=$1

#For loop to iterate the year(key) value of array
for year in ${!arr[@]}; do
  echo  ${year} ${arr[${year}]}
  MONTH_RANGE=${arr[${year}]}
  if [ ${year} -ge ${INPUT_YEAR} ]; then
    START_MONTH=$(echo "${MONTH_RANGE}" | cut -d'%' -f 1)
    END_MONTH=$(echo "${MONTH_RANGE}" | cut -d'%' -f 2)
    # input year is equal and input month is different from default start one.
    if [ "${year}" == "${INPUT_YEAR}" ]; then
      START_MONTH=$INPUT_MONTH
    fi
    for mon in $(seq $START_MONTH $END_MONTH); do
      echo "Process year:month <=> ${year}:${mon}"
    done;
  else
    continue;
  fi
done;

输出:

2019 1%12
Process year:month <=> 2019:1
Process year:month <=> 2019:2
Process year:month <=> 2019:3
Process year:month <=> 2019:4
Process year:month <=> 2019:5
Process year:month <=> 2019:6
Process year:month <=> 2019:7
Process year:month <=> 2019:8
Process year:month <=> 2019:9
Process year:month <=> 2019:10
Process year:month <=> 2019:11
Process year:month <=> 2019:12
2018 5%12
Process year:month <=> 2018:4
Process year:month <=> 2018:5
Process year:month <=> 2018:6
Process year:month <=> 2018:7
Process year:month <=> 2018:8
Process year:month <=> 2018:9
Process year:month <=> 2018:10
Process year:month <=> 2018:11
Process year:month <=> 2018:12
2020 1%2
Process year:month <=> 2020:1
Process year:month <=> 2020:2

答案1

在 bash 中,declare -A arr声明一个联想性的大批。关联数组中的键经过散列处理,并且${!arr[@]}不保证 的遍历顺序1

$ declare -A arr
$ arr=( ["2018"]=5%12 ["2019"]=1%12 ["2020"]=1%2 )
$ for year in "${!arr[@]}"; do printf '%s: %s\n' "${year}" "${arr[${year}]}"; done
2019: 1%12
2018: 5%12
2020: 1%2

相反,declare -a arr声明一个索引数组,它应该按您的预期排序:

$ declare -a arr
$ arr=( [2018]=5%12 [2019]=1%12 [2020]=1%2 )
$ for year in "${!arr[@]}"; do printf '%s: %s\n' "${year}" "${arr[${year}]}"; done
2018: 5%12
2019: 1%12
2020: 1%2

由于您的键(年份)是数字,因此似乎没有理由不在这种情况下使用索引数组。


参考:

  1. 如何保持关联数组的顺序?

答案2

在这种情况下,键恰好是数字,因此您可以使用 Steeldriver 的解决方案。

一般方法是为键顺序提供一个附加数组:

declare -a ordered_keys
ordered_keys=(2018 2019 2020)
# or dynamically
ordered_keys=($(for key in "${!arr[@]}"; do printf '%s\n' "$key"; done | sort))

然后代替

for year in ${!arr[@]}; do

你做

for key in "${ordered_keys[@]}"; do

相关内容