How a sort associative array bash script

How do I sort an associative array in bash?

For example, I have array in bash:

[0,0]="Max"
[0,1]="25"
[1,0]="Vladimir"
[1,1]="0"
[2,0]="Mayki"
[2,1]="50"

Output must be:

  1. Mayki - 50
  2. Max - 25
  3. Vladimir - 0

I don't know how sort this array.

Additional Info: I parse assoc array from text file ("log.txt")

    #!/bin/bash

declare -A b_array

# Read the file in parameter and fill the array named "array"
getArray() {

    i=0
    w=9

    count=10

    while read line # Read a line
    do
        k=0
        #array[i]=$line # Put it into the array

        #b_array[$i,0]=$(grep -Eo "(http|https)://[a-zA-Z0-9./?=_-]*" <<<"$line") 

        for word in $line;
          do  
                  #echo $k;
                  #echo $word;
                  if [ "$k" = "$w" ]; then
                      if [ $word != "-" ]; then
                        b_array[$i]=$word 
                        i=$(($i + 1))
                      fi 

                  fi 
                  k=$(($k + 1))
            done


    done < $1
}

getArray "log.txt"

Upvotes: 1

Views: 1922

Answers (2)

David C. Rankin
David C. Rankin

Reputation: 84561

There are a couple of approaches to this problem. One of the easiest is probably to read the pairs of strings into an indexed array and then reverse numeric sort on the number field:

#!/bin/bash

declare -A arr
declare -a sa

arr[0,0]="Max"
arr[0,1]="25"
arr[1,0]="Vladimir"
arr[1,1]="0"
arr[2,0]="Mayki"
arr[2,1]="50"

## convert associative array to 
#  indexed array of string pairs
#  (e.g. "Max - 25", "Mayki - 50" )
for i in ${!arr[@]}; do                         # for each key in ar

    x=${i%,*}                                   # separate x,y values
    y=${i#*,}
    (( y == 1 )) && continue                    # if y == 1, continue

    for j in ${!arr[@]}; do                     # for each key in ar

        _x=${j%,*}                              # separate _x,_y values
        _y=${j#*,}
        ((x != _x)) || ((_y == 0)) && continue  # if x != _x, or _y == 0, continue

        sa+=( "${arr[$i]} - ${arr[$j]}" )       # add combined string to indexed sa

    done
done

sort -r -k3 -n <<<"$(printf "%s\n" "${sa[@]}")" # numeric reverse sort sa on key3

exit 0

Output

$ bash sort_assoc.sh
Mayki - 50
Max - 25
Vladimir - 0

Upvotes: 1

choroba
choroba

Reputation: 241898

I'd probably switch to Perl for such a complicated task, even if it's still doable in bash:

#!/bin/bash

declare -A arr
arr=([0,0]="Max"
     [0,1]="25"
     [1,0]="Vladimir"
     [1,1]="0"
     [2,0]="Mayki"
     [2,1]="50"
     [10,0]=Ivan
     [10,1]=10
    )

indices=( $( (IFS=$'\n' ; echo "${!arr[*]}") | grep ,0 | cut -d, -f1 | sort ) )

for i in "${indices[@]}" ; do
    echo ${arr[$i,0]} ${arr[$i,1]}
done | sort -rnk2

It would be much simpler if you defined the array like

arr=([Max]=25
     [Vladimir]=0
     [Mayki]=50
     [Ivan]=10
    )

for paren in "${!arr[@]}" ; do
    echo $paren ${arr[$paren]}
done | sort -rnk2

Upvotes: 1

Related Questions