Bash - 按升序对内存中关联数组的键进行排序?

问题描述 投票:0回答:1

这个 Bash 函数是我最近编写的脚本的一部分(下面是带有示例数据的脚本的最小工作示例,包括函数的调用):

#!/bin/bash

declare -A result

stopSchedule='[{"stopId":41571,"lineId":1,"routeId":28,"remainingTime":[3450,8970,13170]},{"stopId":41571,"lineId":2,"routeId":29,"remainingTime":[1410,7950,12750]},{"stopId":41571,"lineId":2,"routeId":30,"remainingTime":[3030,9570,14370]},{"stopId":41571,"lineId":13,"routeId":36,"remainingTime":[3210,7410]},{"stopId":41571,"lineId":6,"routeId":39,"remainingTime":[3090,8790,13110]},{"stopId":41571,"lineId":8,"routeId":43,"remainingTime":[524,4590,9030]},{"stopId":41571,"lineId":8,"routeId":44,"remainingTime":[2190,6150,10590]},{"stopId":41571,"lineId":12,"routeId":52,"remainingTime":[1590]},{"stopId":41571,"lineId":10,"routeId":54,"remainingTime":[2970]}]'
stopsData='[{"id":41571,"areaId":1,"number":"44","name":"МБАЛ Добрич","translations":{},"lat":43.56184005737305,"lon":27.818910598754883,"note":""}]'
routesData='[{"id":44,"lineId":8,"direction":"Практикер-Депо","name":"Практикер-Депо","begin":1682629200,"end":0,"length":9876,"stopIds":[41674,41822,41630,41747,41750,41806,41681,41718,41745,41552,41576,41571,41731,41589,41627,41802,41643,41590,41625,41600,41694,41604,41676,41579,41654,41641,41595],"stopOffsets":[0,120,180,240,300,360,480,540,600,660,720,780,840,900,960,1020,1080,1140,1260,1320,1380,1440,1500,1560,1620,1680,1740]},{"id":43,"lineId":8,"direction":"Депо-Практикер","name":"Депо-Практикер","begin":1682629200,"end":0,"length":10076,"stopIds":[41595,41641,41655,41578,41675,41603,41695,41624,41591,41642,41803,41626,41588,41602,41571,41658,41746,41717,41682,41807,41749,41748,41724,41631,41629,41674],"stopOffsets":[0,60,120,180,240,300,360,420,480,540,600,660,720,780,900,960,1020,1080,1140,1260,1320,1380,1440,1500,1560,1680]},{"id":39,"lineId":6,"direction":"Балик-Дружба-Център","name":"Балик-Дружба-Център","begin":1682629200,"end":0,"length":10237,"stopIds":[41688,41689,41710,41559,41686,41791,41567,41703,41636,41743,41612,41613,41617,41529,41615,41548,41805,41681,41665,41773,41576,41571,41658,41623,41764,41627,41802],"stopOffsets":[0,60,120,180,300,360,480,540,660,720,840,900,960,1080,1140,1200,1260,1320,1380,1440,1500,1560,1620,1740,1800,1860,1920]},{"id":29,"lineId":2,"direction":"Балик-Старт","name":"Балик-Старт","begin":1682542801,"end":0,"length":11100,"stopIds":[41688,41689,41710,41786,41559,41686,41693,41634,41565,41632,41795,41793,41536,41652,41821,41619,41681,41718,41745,41552,41576,41571,41731,41589,41627,41767,41734,41684,41692],"stopOffsets":[0,60,120,180,300,360,480,540,600,720,780,840,900,960,1020,1140,1260,1380,1440,1500,1620,1680,1740,1800,1860,1980,2040,2100,2160]},{"id":28,"lineId":1,"direction":"АПК-Строител","name":"АПК-Строител","begin":1682542801,"end":0,"length":9655,"stopIds":[41687,41545,41719,41580,41645,41647,41571,41658,41746,41717,41682,41608,41701,41811,41582,41728,41649,41594,41787,41711,41568,41754,41792,41910,41693],"stopOffsets":[0,60,180,300,360,420,540,600,660,780,840,900,960,1020,1080,1140,1200,1260,1320,1380,1440,1560,1620,1681,1740]},{"id":30,"lineId":2,"direction":"Старт-Балик","name":"Старт-Балик","begin":1682542801,"end":0,"length":11140,"stopIds":[41692,41683,41733,41768,41626,41588,41602,41571,41658,41746,41717,41682,41620,41666,41653,41537,41794,41796,41633,41912,41910,41693,41685,41787,41711,41688],"stopOffsets":[0,60,120,180,300,360,420,540,600,660,720,780,900,960,1080,1140,1200,1320,1380,1500,1560,1620,1740,1860,1920,1980]},{"id":52,"lineId":12,"direction":"Липите-Център","name":"Липите-Център","begin":1682629200,"end":0,"length":7705,"stopIds":[41669,41677,41679,41722,41551,41660,41799,41698,41818,41671,41605,41781,41576,41571,41658,41746,41717,41682,41608,41701,41811,41716],"stopOffsets":[0,120,180,300,360,420,540,600,660,720,840,900,960,1020,1080,1140,1260,1320,1380,1440,1500,1620]},{"id":34,"lineId":4,"direction":"Гробищен парк-Депо","name":"Гробищен парк-Депо","begin":1682629200,"end":0,"length":14352,"stopIds":[41592,41663,41809,41574,41724,41631,41629,41674,41628,41541,41616,41528,41618,41564,41594,41787,41711,41568,41754,41566,41632,41695,41789,41763,41570,41639,41534,41713,41759,41725,41585,41579,41654,41641,41595],"stopOffsets":[0,60,120,180,300,360,420,540,600,660,780,840,960,1080,1200,1320,1380,1440,1560,1680,1800,1860,1920,2040,2100,2160,2220,2280,2340,2400,2460,2520,2640,2700,2760]},{"id":54,"lineId":10,"direction":"Добротица-Рилци","name":"Добротица-Рилци","begin":1691960400,"end":0,"length":13838,"stopIds":[41724,41631,41629,41541,41805,41620,41666,41820,41653,41537,41753,41700,41681,41665,41773,41576,41571,41658,41623,41815,41709,41803,41829,41752,41766,41812,41816,41729,41690],"stopOffsets":[0,60,120,180,240,300,360,370,480,540,600,720,840,900,960,1020,1080,1140,1200,1260,1320,1440,1500,1620,1740,1860,1920,2040,2100]},{"id":36,"lineId":13,"direction":"Гробищен парк-Депо","name":"Гробищен парк-Депо","begin":1682629200,"end":0,"length":9814,"stopIds":[41592,41663,41809,41574,41747,41750,41806,41681,41665,41773,41571,41731,41589,41627,41715,41547,41570,41639,41534,41713,41759,41725,41585,41579,41654,41595],"stopOffsets":[0,60,120,180,300,360,480,600,720,780,900,960,1020,1080,1140,1200,1260,1320,1380,1440,1500,1560,1620,1680,1740,1800]}]'

function stopNameAndNumById {
    echo $stopsData | jq -r --arg id "$1" '.[] | select(.id == ($id | tonumber)) | "\(.number),\(.name)"'
}

function collectLinesDesc {
    if [ -z "$linesDesc" ]; then
        linesDesc='[{"id":13,"kind":"BUS","number":"4а","name":"Линия 4A","nightly":false,"routeIds":[35,36],"type":"URBAN","carrier":"X"}]'
    fi
}

function linesFromStopId {
    IFS=', ' read -ra id_arr <<< "$1"
    i=true

    for id in "${id_arr[@]}"; do
        stopNumName=$(stopNameAndNumById "$id")
        for row in $(echo "$stopSchedule" | jq -c -r '.[] | {lineId, remainingTime, routeId}'); do
            lineId=$(echo "$row" | jq -r '.lineId')
            routeId=$(echo "$row" | jq -r '.routeId')
            remainingTime=$(echo "$row" | jq -r '.remainingTime[0]')
            routeName=$(echo "$routesData" | jq -r '.[] | select(.id == '$routeId') | .name')
            remainingTimeInMinutes=$((remainingTime / 60))
            key=$lineId
            while [[ -n "${result[$key]}" ]]; do
                key="${key}_"
            done
            result["$key"]="$remainingTimeInMinutes,$routeName"
        done
        [ $i = true ] && i=false || echo
        echo -e "Спирка $(cut -d',' -f2 <<< $stopNumName) ($(cut -d',' -f1 <<< $stopNumName))\n"
        for key in "${!result[@]}"; do
            newKey="$key"
            if [[ $key == *_ ]]; then
                newKey="${key%_}"
            fi
            IFS=',' read -ra values <<< "${result[$key]}"
            if [ $newKey -gt "12" ]; then
                collectLinesDesc
                newKey=$(echo $linesDesc | jq -r --arg id "$newKey" '.[] | select(.id == ($id | tonumber)) | .number' | awk '{ print toupper($0) }')
            fi
            echo "Линия $newKey (${values[1]}) - ${values[0]} минути"
        done
        result=()
    done
}

linesFromStopId "41571"

我正在寻找一种优雅的方法来在内存中按升序对

$result
关联数组的键进行排序,而不是在我将数据打印到输出时。

while [[ -n "${result[$key]}" ]]; do
循环之前,保证数组的键仅包含数字(一位或两位数字长)。

collectLinesDesc
从 RESTful API 收集公交线路的描述(如果我们之前尚未收集过的话)。

最小工作示例的当前输出将是:

Спирка МБАЛ Добрич (44)

Линия 8 (Практикер-Депо) - 0 м.
Линия 8 (Депо-Практикер) - 0 м.
Линия 6 (Балик-Дружба-Център) - 0 м.
Линия 2 (Балик-Старт) - 0 м.
Линия 1 (АПК-Строител) - 0 м.
Линия 2 (Старт-Балик) - 0 м.
Линия 12 (Липите-Център) - 0 м.
Линия 4А (Гробищен парк-Депо) - 0 м.
Линия 10 (Добротица-Рилци) - 0 м.

预期输出(“Линия”后面的数字升序排列):

Спирка МБАЛ Добрич (44)

Линия 1 (Практикер-Депо) - 0 м.
Линия 2 (Депо-Практикер) - 0 м.
Линия 2 (Балик-Дружба-Център) - 0 м.
Линия 6 (Балик-Старт) - 0 м.
Линия 8 (АПК-Строител) - 0 м.
Линия 8 (Старт-Балик) - 0 м.
Линия 10 (Липите-Център) - 0 м.
Линия 12 (Гробищен парк-Депо) - 0 м.
Линия 4A (Добротица-Рилци) - 0 м.

(这里的“4A”是一个显示值,在数组中会是一个大于12的数字,所以升序排列总是在最后,所以逻辑和显示逻辑一致)

我能想到的一种方法是让

jq
从按
lineId
排序的 JSON 中输出数据,然后使用第二个索引数组来保持条目的顺序,然后使用该索引数组作为关联数组
$result
当我在最终输出数据的循环中迭代它时,但是有没有更好/更短/更简单的方法来在 Bash 中实现相同的目的?

bash sorting associative-array
1个回答
0
投票

您可以使用

result
而不是
-a
来简单地保持
-A
的顺序。

例如:

# declare -A result
declare -a result
# ...
            # key=$lineId
            (( key = lineId*1000 ))
            while [[ -n "${result[$key]}" ]]; do
                # key="${key}_"
                (( key++ ))
            done
# ...
        for key in "${!result[@]}"; do
            # newKey="$key"
            # if [[ $key == *_ ]]; then
            #    newKey="${key%_}"
            # fi
            (( newKey = key/1000 ))
# ...

但这会产生与请求不同的输出:

Спирка МБАЛ Добрич (44)

Линия 1 (АПК-Строител) - 57 минути
Линия 2 (Балик-Старт) - 23 минути
Линия 2 (Старт-Балик) - 50 минути
Линия 6 (Балик-Дружба-Център) - 51 минути
Линия 8 (Депо-Практикер) - 8 минути
Линия 8 (Практикер-Депо) - 36 минути
Линия 10 (Добротица-Рилци) - 49 минути
Линия 12 (Липите-Център) - 26 минути
Линия 4А (Гробищен парк-Депо) - 53 минути

非常不清楚为什么您期望对键进行排序会更改存储在数组中的值。

© www.soinside.com 2019 - 2024. All rights reserved.