1

I need to sort the following array by two keys, score and alphabetically.

For example:

arr = (Hawrd 60 James 75 Jacob 60 Leonard 75) 

will become :

sorted = (Hawrd 60 Jacob 60 James 75 Leonard 75)

*actually I don't need the sorted array, just need to print it (in a format of name and a score). Thanks! *I read about the command sort but I dont see how can I sort by two keys using that command

EDIT: Sorry if it wasn't clear enought, but I meant that each person has its own score, Leonard has 75, Jacob has 60 and in the end of the process, each person will still have the same score.

2
  • Sorry if I am being dense, but I can't tell from your example whether you want them sorted first by score then by name, or first by name then by score because the output is sorted by both name and score - isn't it? Maybe I am going mad. Commented Mar 22, 2014 at 10:45
  • First by score and then by name. Commented Mar 22, 2014 at 10:49

3 Answers 3

1

I'm not sure if that answers the question, but with this few details provided I'll try

Here is one solution :

 [ ~]$ cat test.sh 
 #!/bin/bash

 declare -a array
 declare -a ageArray
 array=("Hawrd 60" "James 75" "Jacob 60" "Leonard 75")
 size=${#array[@]}

 for (( i=0 ; i < $size ; i++ )); do
     age=$(echo "${array[$i]}"|egrep -o "[0-9]*")
     ageArray[$i]="$age_${array[$i]}"
 done

 # sorting by age and by name (with ascii comparison)
 for (( i=0 ; i < $size ; i++ )); do
     for (( j=$i+1 ; j < $size ; j++ )); do
         if [[ ${ageArray[$j]} < ${ageArray[$i]} ]]; then
             tmp="${array[$i]}"
             ageTmp="${ageArray[$i]}"

             array[$i]="${array[$j]}"
             ageArray[$i]="${ageArray[$j]}"

             array[$j]="$tmp"
             ageArray[$j]="$ageTmp"
         fi
     done 
 done

 #printing result
 for item in "${array[@]}"; do
     echo "$item"
 done
 [ ~]$ ./test.sh 
 Hawrd 60
 Jacob 60
 James 75
 Leonard 75
Sign up to request clarification or add additional context in comments.

Comments

1

Here is one method:

arr=( Hawrd 60 James 75 Jacob 60 Leonard 75 )

#first we sort the array like this: 60 60 75 75 Hawrd James Jacob Leonard
OLDIFS=$IFS
IFS=$'\n' arr_sorted=($(sort <<<"${arr[*]}"))
IFS=$OLDIFS

#second, we split the sorted array in two: numbers and names
cnt="${#arr_sorted[@]}"
let cnt1="$cnt/2"
let cnt2="$cnt - $cnt1"
nr_sorted=( "${arr_sorted[@]:0:$cnt1}" )
names_sorted=( "${arr_sorted[@]:$cnt1:$cnt2}" )

#and third, we combine the new arrays(names ang numbers) element by element
for ((i=0;i<${#names_sorted[@]};i++)); do sorted+=(${names_sorted[i]} ${nr_sorted[i]});done

#now the array 'sorted' contain exactly what you wished; let's print it
echo "${sorted[*]}"

2 Comments

Thanks! I may be wrong but I think your solution doesn't keep the correct order, I mean this array is like a Key,Value: Leonard has the score of 75, Jacob got 60 and etc. When I want to sort it, each person will still have his own score but in the right place.
@Michael That's exactly what's happening. If you run the above lines you will see that the output is Hawrd 60 Jacob 60 James 75 Leonard 75 ...exactly as you asked. Just take your time and test it: copy the above lines and paste them in terminal, nothing more.
0

If you don't mind Perl, you can do it like this:

#!/bin/bash
arr=(Zigbee 9 Hawrd 60 Apple 99 James 75 Jacob 60 Leonard 75) 
echo -n ${arr[@]} | perl -040 -nE 'if(defined($a)){push(@l,{Name=>$a,Score=>$_});undef $a}else{$a=$_};END{foreach(sort {$$a{Score} <=> $$b{Score} or $$a{Name} cmp $$b{Name}} @l){say "$$_{Name} $$_{Score}"}}'

The elements of the array are echoed and each one is read at a time by making Perl's record separator the space (-040). One name is read into $a, and then on the next read, as $a ids defined, the next value is read in $b. $a and $b are then pushed onto the end of an array of hashes. At the end (END), the array is sorted by score and name and the names and scores printed out.

Output:

Zigbee 9
Hawrd 60
Jacob 60
James 75
Leonard 75
Apple 99

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.