What's the right way to sort a associated array in bash or zsh?












7















I'm wondering how should I sort the associated array in bash? I tried the manual, but seems nothing related to sort.



The current solution is echo everything out, and use external program i.e key value | sort -k2



That looks inefficient to me.



An example of array was:



A['192.168.2.2']=5
A['192.168.3.2']=1
A['192.168.1.1']=9


And I'll be looking for the top 2 used IP address, which is 192.168.1.1 and 192.168.2.2, that is, I need to sort this array by it's value.










share|improve this question

























  • It sounds like what you are trying to accomplish is too complex for bash to do easily. What are you trying to do?

    – jw013
    Oct 16 '12 at 15:10











  • And asking for the "right" way is just asking for trouble. ;)

    – lynxlynxlynx
    Oct 16 '12 at 17:09











  • mywiki.wooledge.org/BashWeaknesses

    – jordanm
    Oct 16 '12 at 20:04











  • Is switching to zsh an option? Otherwise, relying on external tools is common in shell programming.

    – Gilles
    Oct 16 '12 at 21:47






  • 1





    If you getting this data from parsing and have gawk available, I tend to just do it all in awk.

    – jordanm
    Oct 17 '12 at 2:40
















7















I'm wondering how should I sort the associated array in bash? I tried the manual, but seems nothing related to sort.



The current solution is echo everything out, and use external program i.e key value | sort -k2



That looks inefficient to me.



An example of array was:



A['192.168.2.2']=5
A['192.168.3.2']=1
A['192.168.1.1']=9


And I'll be looking for the top 2 used IP address, which is 192.168.1.1 and 192.168.2.2, that is, I need to sort this array by it's value.










share|improve this question

























  • It sounds like what you are trying to accomplish is too complex for bash to do easily. What are you trying to do?

    – jw013
    Oct 16 '12 at 15:10











  • And asking for the "right" way is just asking for trouble. ;)

    – lynxlynxlynx
    Oct 16 '12 at 17:09











  • mywiki.wooledge.org/BashWeaknesses

    – jordanm
    Oct 16 '12 at 20:04











  • Is switching to zsh an option? Otherwise, relying on external tools is common in shell programming.

    – Gilles
    Oct 16 '12 at 21:47






  • 1





    If you getting this data from parsing and have gawk available, I tend to just do it all in awk.

    – jordanm
    Oct 17 '12 at 2:40














7












7








7


2






I'm wondering how should I sort the associated array in bash? I tried the manual, but seems nothing related to sort.



The current solution is echo everything out, and use external program i.e key value | sort -k2



That looks inefficient to me.



An example of array was:



A['192.168.2.2']=5
A['192.168.3.2']=1
A['192.168.1.1']=9


And I'll be looking for the top 2 used IP address, which is 192.168.1.1 and 192.168.2.2, that is, I need to sort this array by it's value.










share|improve this question
















I'm wondering how should I sort the associated array in bash? I tried the manual, but seems nothing related to sort.



The current solution is echo everything out, and use external program i.e key value | sort -k2



That looks inefficient to me.



An example of array was:



A['192.168.2.2']=5
A['192.168.3.2']=1
A['192.168.1.1']=9


And I'll be looking for the top 2 used IP address, which is 192.168.1.1 and 192.168.2.2, that is, I need to sort this array by it's value.







bash zsh






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Oct 17 '12 at 8:18









manatwork

21.9k38384




21.9k38384










asked Oct 16 '12 at 14:57









daisydaisy

28.8k49171302




28.8k49171302













  • It sounds like what you are trying to accomplish is too complex for bash to do easily. What are you trying to do?

    – jw013
    Oct 16 '12 at 15:10











  • And asking for the "right" way is just asking for trouble. ;)

    – lynxlynxlynx
    Oct 16 '12 at 17:09











  • mywiki.wooledge.org/BashWeaknesses

    – jordanm
    Oct 16 '12 at 20:04











  • Is switching to zsh an option? Otherwise, relying on external tools is common in shell programming.

    – Gilles
    Oct 16 '12 at 21:47






  • 1





    If you getting this data from parsing and have gawk available, I tend to just do it all in awk.

    – jordanm
    Oct 17 '12 at 2:40



















  • It sounds like what you are trying to accomplish is too complex for bash to do easily. What are you trying to do?

    – jw013
    Oct 16 '12 at 15:10











  • And asking for the "right" way is just asking for trouble. ;)

    – lynxlynxlynx
    Oct 16 '12 at 17:09











  • mywiki.wooledge.org/BashWeaknesses

    – jordanm
    Oct 16 '12 at 20:04











  • Is switching to zsh an option? Otherwise, relying on external tools is common in shell programming.

    – Gilles
    Oct 16 '12 at 21:47






  • 1





    If you getting this data from parsing and have gawk available, I tend to just do it all in awk.

    – jordanm
    Oct 17 '12 at 2:40

















It sounds like what you are trying to accomplish is too complex for bash to do easily. What are you trying to do?

– jw013
Oct 16 '12 at 15:10





It sounds like what you are trying to accomplish is too complex for bash to do easily. What are you trying to do?

– jw013
Oct 16 '12 at 15:10













And asking for the "right" way is just asking for trouble. ;)

– lynxlynxlynx
Oct 16 '12 at 17:09





And asking for the "right" way is just asking for trouble. ;)

– lynxlynxlynx
Oct 16 '12 at 17:09













mywiki.wooledge.org/BashWeaknesses

– jordanm
Oct 16 '12 at 20:04





mywiki.wooledge.org/BashWeaknesses

– jordanm
Oct 16 '12 at 20:04













Is switching to zsh an option? Otherwise, relying on external tools is common in shell programming.

– Gilles
Oct 16 '12 at 21:47





Is switching to zsh an option? Otherwise, relying on external tools is common in shell programming.

– Gilles
Oct 16 '12 at 21:47




1




1





If you getting this data from parsing and have gawk available, I tend to just do it all in awk.

– jordanm
Oct 17 '12 at 2:40





If you getting this data from parsing and have gawk available, I tend to just do it all in awk.

– jordanm
Oct 17 '12 at 2:40










4 Answers
4






active

oldest

votes


















3














Zsh has a built-in way to sort lists. However, I don't think there's a way to sort the values while keeping the correlation with the keys using parameter expansion flags and subscript flags, which means that an explicit loop is necessary. Assuming that your values don't contain a null character, you can build an array containing the values and keys concatenated with a null character in between, and sort that.



keys=("${(@k)A}")
values=("${(@v)A}")
combined=()
for ((i=1; i <= $#values; i++)) { combined[i]=($values[i]$''$keys[i]); }
keys_sorted_by_decreasing_value=("${${(@On)combined}#*$''}")
keys_of_the_top_two_values=("${(@)keys_sorted_by_decreasing_value[1,2]}")


EDIT by @sch: the first 4 lines can be simplified to



combined=()
for k v ("${(@kv)A}") combined+=($k$''$v)


The variables keys and values contain the keys and values of A in an arbitrary but consistent order. You can write keys=(${(k)A}) if there are no empty keys, and similarly for values. keys_sorted_by_decreasing_value sorts keys lexicographically, add the n flag to sort numerically (9 before 10) and remove O if you want to sort in increasing order (in which case the top two values can be obtained with the subscript [-2,-1]).



Ksh93 has a way to sort the positional parameters only, with set -s; this also exists in zsh but not in bash 4.2. Assuming your values don't contain newlines or control characters that sort before newlines:



keys=("${!A[@]}")
combined=()
for ((i=0; i <= ${#keys}; i++)); do combined[i]=(${A[${keys[$i]}]}$'n'${keys[$i]}); done
set -A sorted -s "${combined[@]}"
top_combined=${sorted[${#sorted[@]}-1]} # -2 for the next-to-largest, etc.
top_key=${top_combined#*$'n'}


This is all pretty complex, so you might as well go for the external sort, which is a lot easier to write. Assuming that neither keys nor values contain control characters, in ksh or bash:



IFS=$'n'; set -f
keys_sorted_by_decreasing_value=($(
for k in "${!A[@]}"; do printf '%st%sn' "${A[$k]}" "$k"; done |
sort | sed $'s/t.*//'
))





share|improve this answer

































    2














    A shell is before all a tool to run other tools. It sounds to me you're after a programming language like perl, ruby, python...



    Having said that, here is some possible solution for zsh.



    In zsh, you can get a sorted list of the keys of an associated array (${(kOn)A}) or of the values (${(On)A}) but not directly a list of keys from the sorted list of values (AFAIK), but you could do things like:



    typeset -A A B
    A=(
    192.168.2.2 5
    192.168.3.2 1
    192.168.1.1 9
    192.168.8.1 9
    )

    for v ("${(@nO)A}") B+=("${(@kv)A[(eR)$v]}")


    That is, order (O) the list of values ($A) numerically (n) and for each value, add the key/value pairs matching the value $v (e for exact match, R to get the reverse list based on value, not key) and add that to the B associative array.



    Then, you'd get the sorted list in B:



    $ printf '%s => %sn' "${(@kv)B}"
    192.168.8.1 => 9
    192.168.1.1 => 9
    192.168.2.2 => 5
    192.168.3.2 => 1


    And you can select the first 2 keys with



    $ print -rl -- ${${(k)B}[1,2]}
    192.168.8.1
    192.168.1.1





    share|improve this answer

































      0














      "Associative Array" often means that the data in array have real-world meaning, which is your case. External unix sort is ideal for this task, and few C programmer can out-perform unix sort. Especially for big data you can tailor, slice, fork, bring full power of unix and shell. This is why so many shell and awk platform there don't bother with a sort.






      share|improve this answer































        0














        The best way to sort a bash associative array by KEY is to NOT sort it.



        Instead, get the list of KEYS, sort that list as a variable, and iterate through the list. Example: Suppose you have an array of IP addresses (keys) and host names (values):



        Alternative:
        Create new list from KEYs, convert to lines, sort it, convert back to list, and use it to iterate through the array.



        declare -A ADDR
        ADDR[192.168.1.1]="host1"
        ADDR[192.168.1.2]="host2"
        etc...

        KEYS=`echo ${!ADDR[@]} | tr ' ' '12' | sort | tr '12' ' '`
        for KEY in $KEYS; do
        VAL=${ADDR[$KEY]}
        echo "KEY=[$KEY] VAL=[$VAL]"
        done





        share|improve this answer























          Your Answer








          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "106"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f51998%2fwhats-the-right-way-to-sort-a-associated-array-in-bash-or-zsh%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          4 Answers
          4






          active

          oldest

          votes








          4 Answers
          4






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          3














          Zsh has a built-in way to sort lists. However, I don't think there's a way to sort the values while keeping the correlation with the keys using parameter expansion flags and subscript flags, which means that an explicit loop is necessary. Assuming that your values don't contain a null character, you can build an array containing the values and keys concatenated with a null character in between, and sort that.



          keys=("${(@k)A}")
          values=("${(@v)A}")
          combined=()
          for ((i=1; i <= $#values; i++)) { combined[i]=($values[i]$''$keys[i]); }
          keys_sorted_by_decreasing_value=("${${(@On)combined}#*$''}")
          keys_of_the_top_two_values=("${(@)keys_sorted_by_decreasing_value[1,2]}")


          EDIT by @sch: the first 4 lines can be simplified to



          combined=()
          for k v ("${(@kv)A}") combined+=($k$''$v)


          The variables keys and values contain the keys and values of A in an arbitrary but consistent order. You can write keys=(${(k)A}) if there are no empty keys, and similarly for values. keys_sorted_by_decreasing_value sorts keys lexicographically, add the n flag to sort numerically (9 before 10) and remove O if you want to sort in increasing order (in which case the top two values can be obtained with the subscript [-2,-1]).



          Ksh93 has a way to sort the positional parameters only, with set -s; this also exists in zsh but not in bash 4.2. Assuming your values don't contain newlines or control characters that sort before newlines:



          keys=("${!A[@]}")
          combined=()
          for ((i=0; i <= ${#keys}; i++)); do combined[i]=(${A[${keys[$i]}]}$'n'${keys[$i]}); done
          set -A sorted -s "${combined[@]}"
          top_combined=${sorted[${#sorted[@]}-1]} # -2 for the next-to-largest, etc.
          top_key=${top_combined#*$'n'}


          This is all pretty complex, so you might as well go for the external sort, which is a lot easier to write. Assuming that neither keys nor values contain control characters, in ksh or bash:



          IFS=$'n'; set -f
          keys_sorted_by_decreasing_value=($(
          for k in "${!A[@]}"; do printf '%st%sn' "${A[$k]}" "$k"; done |
          sort | sed $'s/t.*//'
          ))





          share|improve this answer






























            3














            Zsh has a built-in way to sort lists. However, I don't think there's a way to sort the values while keeping the correlation with the keys using parameter expansion flags and subscript flags, which means that an explicit loop is necessary. Assuming that your values don't contain a null character, you can build an array containing the values and keys concatenated with a null character in between, and sort that.



            keys=("${(@k)A}")
            values=("${(@v)A}")
            combined=()
            for ((i=1; i <= $#values; i++)) { combined[i]=($values[i]$''$keys[i]); }
            keys_sorted_by_decreasing_value=("${${(@On)combined}#*$''}")
            keys_of_the_top_two_values=("${(@)keys_sorted_by_decreasing_value[1,2]}")


            EDIT by @sch: the first 4 lines can be simplified to



            combined=()
            for k v ("${(@kv)A}") combined+=($k$''$v)


            The variables keys and values contain the keys and values of A in an arbitrary but consistent order. You can write keys=(${(k)A}) if there are no empty keys, and similarly for values. keys_sorted_by_decreasing_value sorts keys lexicographically, add the n flag to sort numerically (9 before 10) and remove O if you want to sort in increasing order (in which case the top two values can be obtained with the subscript [-2,-1]).



            Ksh93 has a way to sort the positional parameters only, with set -s; this also exists in zsh but not in bash 4.2. Assuming your values don't contain newlines or control characters that sort before newlines:



            keys=("${!A[@]}")
            combined=()
            for ((i=0; i <= ${#keys}; i++)); do combined[i]=(${A[${keys[$i]}]}$'n'${keys[$i]}); done
            set -A sorted -s "${combined[@]}"
            top_combined=${sorted[${#sorted[@]}-1]} # -2 for the next-to-largest, etc.
            top_key=${top_combined#*$'n'}


            This is all pretty complex, so you might as well go for the external sort, which is a lot easier to write. Assuming that neither keys nor values contain control characters, in ksh or bash:



            IFS=$'n'; set -f
            keys_sorted_by_decreasing_value=($(
            for k in "${!A[@]}"; do printf '%st%sn' "${A[$k]}" "$k"; done |
            sort | sed $'s/t.*//'
            ))





            share|improve this answer




























              3












              3








              3







              Zsh has a built-in way to sort lists. However, I don't think there's a way to sort the values while keeping the correlation with the keys using parameter expansion flags and subscript flags, which means that an explicit loop is necessary. Assuming that your values don't contain a null character, you can build an array containing the values and keys concatenated with a null character in between, and sort that.



              keys=("${(@k)A}")
              values=("${(@v)A}")
              combined=()
              for ((i=1; i <= $#values; i++)) { combined[i]=($values[i]$''$keys[i]); }
              keys_sorted_by_decreasing_value=("${${(@On)combined}#*$''}")
              keys_of_the_top_two_values=("${(@)keys_sorted_by_decreasing_value[1,2]}")


              EDIT by @sch: the first 4 lines can be simplified to



              combined=()
              for k v ("${(@kv)A}") combined+=($k$''$v)


              The variables keys and values contain the keys and values of A in an arbitrary but consistent order. You can write keys=(${(k)A}) if there are no empty keys, and similarly for values. keys_sorted_by_decreasing_value sorts keys lexicographically, add the n flag to sort numerically (9 before 10) and remove O if you want to sort in increasing order (in which case the top two values can be obtained with the subscript [-2,-1]).



              Ksh93 has a way to sort the positional parameters only, with set -s; this also exists in zsh but not in bash 4.2. Assuming your values don't contain newlines or control characters that sort before newlines:



              keys=("${!A[@]}")
              combined=()
              for ((i=0; i <= ${#keys}; i++)); do combined[i]=(${A[${keys[$i]}]}$'n'${keys[$i]}); done
              set -A sorted -s "${combined[@]}"
              top_combined=${sorted[${#sorted[@]}-1]} # -2 for the next-to-largest, etc.
              top_key=${top_combined#*$'n'}


              This is all pretty complex, so you might as well go for the external sort, which is a lot easier to write. Assuming that neither keys nor values contain control characters, in ksh or bash:



              IFS=$'n'; set -f
              keys_sorted_by_decreasing_value=($(
              for k in "${!A[@]}"; do printf '%st%sn' "${A[$k]}" "$k"; done |
              sort | sed $'s/t.*//'
              ))





              share|improve this answer















              Zsh has a built-in way to sort lists. However, I don't think there's a way to sort the values while keeping the correlation with the keys using parameter expansion flags and subscript flags, which means that an explicit loop is necessary. Assuming that your values don't contain a null character, you can build an array containing the values and keys concatenated with a null character in between, and sort that.



              keys=("${(@k)A}")
              values=("${(@v)A}")
              combined=()
              for ((i=1; i <= $#values; i++)) { combined[i]=($values[i]$''$keys[i]); }
              keys_sorted_by_decreasing_value=("${${(@On)combined}#*$''}")
              keys_of_the_top_two_values=("${(@)keys_sorted_by_decreasing_value[1,2]}")


              EDIT by @sch: the first 4 lines can be simplified to



              combined=()
              for k v ("${(@kv)A}") combined+=($k$''$v)


              The variables keys and values contain the keys and values of A in an arbitrary but consistent order. You can write keys=(${(k)A}) if there are no empty keys, and similarly for values. keys_sorted_by_decreasing_value sorts keys lexicographically, add the n flag to sort numerically (9 before 10) and remove O if you want to sort in increasing order (in which case the top two values can be obtained with the subscript [-2,-1]).



              Ksh93 has a way to sort the positional parameters only, with set -s; this also exists in zsh but not in bash 4.2. Assuming your values don't contain newlines or control characters that sort before newlines:



              keys=("${!A[@]}")
              combined=()
              for ((i=0; i <= ${#keys}; i++)); do combined[i]=(${A[${keys[$i]}]}$'n'${keys[$i]}); done
              set -A sorted -s "${combined[@]}"
              top_combined=${sorted[${#sorted[@]}-1]} # -2 for the next-to-largest, etc.
              top_key=${top_combined#*$'n'}


              This is all pretty complex, so you might as well go for the external sort, which is a lot easier to write. Assuming that neither keys nor values contain control characters, in ksh or bash:



              IFS=$'n'; set -f
              keys_sorted_by_decreasing_value=($(
              for k in "${!A[@]}"; do printf '%st%sn' "${A[$k]}" "$k"; done |
              sort | sed $'s/t.*//'
              ))






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Oct 17 '12 at 13:46









              Stéphane Chazelas

              306k57577931




              306k57577931










              answered Oct 17 '12 at 12:56









              GillesGilles

              538k12810881605




              538k12810881605

























                  2














                  A shell is before all a tool to run other tools. It sounds to me you're after a programming language like perl, ruby, python...



                  Having said that, here is some possible solution for zsh.



                  In zsh, you can get a sorted list of the keys of an associated array (${(kOn)A}) or of the values (${(On)A}) but not directly a list of keys from the sorted list of values (AFAIK), but you could do things like:



                  typeset -A A B
                  A=(
                  192.168.2.2 5
                  192.168.3.2 1
                  192.168.1.1 9
                  192.168.8.1 9
                  )

                  for v ("${(@nO)A}") B+=("${(@kv)A[(eR)$v]}")


                  That is, order (O) the list of values ($A) numerically (n) and for each value, add the key/value pairs matching the value $v (e for exact match, R to get the reverse list based on value, not key) and add that to the B associative array.



                  Then, you'd get the sorted list in B:



                  $ printf '%s => %sn' "${(@kv)B}"
                  192.168.8.1 => 9
                  192.168.1.1 => 9
                  192.168.2.2 => 5
                  192.168.3.2 => 1


                  And you can select the first 2 keys with



                  $ print -rl -- ${${(k)B}[1,2]}
                  192.168.8.1
                  192.168.1.1





                  share|improve this answer






























                    2














                    A shell is before all a tool to run other tools. It sounds to me you're after a programming language like perl, ruby, python...



                    Having said that, here is some possible solution for zsh.



                    In zsh, you can get a sorted list of the keys of an associated array (${(kOn)A}) or of the values (${(On)A}) but not directly a list of keys from the sorted list of values (AFAIK), but you could do things like:



                    typeset -A A B
                    A=(
                    192.168.2.2 5
                    192.168.3.2 1
                    192.168.1.1 9
                    192.168.8.1 9
                    )

                    for v ("${(@nO)A}") B+=("${(@kv)A[(eR)$v]}")


                    That is, order (O) the list of values ($A) numerically (n) and for each value, add the key/value pairs matching the value $v (e for exact match, R to get the reverse list based on value, not key) and add that to the B associative array.



                    Then, you'd get the sorted list in B:



                    $ printf '%s => %sn' "${(@kv)B}"
                    192.168.8.1 => 9
                    192.168.1.1 => 9
                    192.168.2.2 => 5
                    192.168.3.2 => 1


                    And you can select the first 2 keys with



                    $ print -rl -- ${${(k)B}[1,2]}
                    192.168.8.1
                    192.168.1.1





                    share|improve this answer




























                      2












                      2








                      2







                      A shell is before all a tool to run other tools. It sounds to me you're after a programming language like perl, ruby, python...



                      Having said that, here is some possible solution for zsh.



                      In zsh, you can get a sorted list of the keys of an associated array (${(kOn)A}) or of the values (${(On)A}) but not directly a list of keys from the sorted list of values (AFAIK), but you could do things like:



                      typeset -A A B
                      A=(
                      192.168.2.2 5
                      192.168.3.2 1
                      192.168.1.1 9
                      192.168.8.1 9
                      )

                      for v ("${(@nO)A}") B+=("${(@kv)A[(eR)$v]}")


                      That is, order (O) the list of values ($A) numerically (n) and for each value, add the key/value pairs matching the value $v (e for exact match, R to get the reverse list based on value, not key) and add that to the B associative array.



                      Then, you'd get the sorted list in B:



                      $ printf '%s => %sn' "${(@kv)B}"
                      192.168.8.1 => 9
                      192.168.1.1 => 9
                      192.168.2.2 => 5
                      192.168.3.2 => 1


                      And you can select the first 2 keys with



                      $ print -rl -- ${${(k)B}[1,2]}
                      192.168.8.1
                      192.168.1.1





                      share|improve this answer















                      A shell is before all a tool to run other tools. It sounds to me you're after a programming language like perl, ruby, python...



                      Having said that, here is some possible solution for zsh.



                      In zsh, you can get a sorted list of the keys of an associated array (${(kOn)A}) or of the values (${(On)A}) but not directly a list of keys from the sorted list of values (AFAIK), but you could do things like:



                      typeset -A A B
                      A=(
                      192.168.2.2 5
                      192.168.3.2 1
                      192.168.1.1 9
                      192.168.8.1 9
                      )

                      for v ("${(@nO)A}") B+=("${(@kv)A[(eR)$v]}")


                      That is, order (O) the list of values ($A) numerically (n) and for each value, add the key/value pairs matching the value $v (e for exact match, R to get the reverse list based on value, not key) and add that to the B associative array.



                      Then, you'd get the sorted list in B:



                      $ printf '%s => %sn' "${(@kv)B}"
                      192.168.8.1 => 9
                      192.168.1.1 => 9
                      192.168.2.2 => 5
                      192.168.3.2 => 1


                      And you can select the first 2 keys with



                      $ print -rl -- ${${(k)B}[1,2]}
                      192.168.8.1
                      192.168.1.1






                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Oct 19 '12 at 6:13

























                      answered Oct 17 '12 at 10:06









                      Stéphane ChazelasStéphane Chazelas

                      306k57577931




                      306k57577931























                          0














                          "Associative Array" often means that the data in array have real-world meaning, which is your case. External unix sort is ideal for this task, and few C programmer can out-perform unix sort. Especially for big data you can tailor, slice, fork, bring full power of unix and shell. This is why so many shell and awk platform there don't bother with a sort.






                          share|improve this answer




























                            0














                            "Associative Array" often means that the data in array have real-world meaning, which is your case. External unix sort is ideal for this task, and few C programmer can out-perform unix sort. Especially for big data you can tailor, slice, fork, bring full power of unix and shell. This is why so many shell and awk platform there don't bother with a sort.






                            share|improve this answer


























                              0












                              0








                              0







                              "Associative Array" often means that the data in array have real-world meaning, which is your case. External unix sort is ideal for this task, and few C programmer can out-perform unix sort. Especially for big data you can tailor, slice, fork, bring full power of unix and shell. This is why so many shell and awk platform there don't bother with a sort.






                              share|improve this answer













                              "Associative Array" often means that the data in array have real-world meaning, which is your case. External unix sort is ideal for this task, and few C programmer can out-perform unix sort. Especially for big data you can tailor, slice, fork, bring full power of unix and shell. This is why so many shell and awk platform there don't bother with a sort.







                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered Oct 19 '12 at 6:48









                              MeaCulpaMeaCulpa

                              31614




                              31614























                                  0














                                  The best way to sort a bash associative array by KEY is to NOT sort it.



                                  Instead, get the list of KEYS, sort that list as a variable, and iterate through the list. Example: Suppose you have an array of IP addresses (keys) and host names (values):



                                  Alternative:
                                  Create new list from KEYs, convert to lines, sort it, convert back to list, and use it to iterate through the array.



                                  declare -A ADDR
                                  ADDR[192.168.1.1]="host1"
                                  ADDR[192.168.1.2]="host2"
                                  etc...

                                  KEYS=`echo ${!ADDR[@]} | tr ' ' '12' | sort | tr '12' ' '`
                                  for KEY in $KEYS; do
                                  VAL=${ADDR[$KEY]}
                                  echo "KEY=[$KEY] VAL=[$VAL]"
                                  done





                                  share|improve this answer




























                                    0














                                    The best way to sort a bash associative array by KEY is to NOT sort it.



                                    Instead, get the list of KEYS, sort that list as a variable, and iterate through the list. Example: Suppose you have an array of IP addresses (keys) and host names (values):



                                    Alternative:
                                    Create new list from KEYs, convert to lines, sort it, convert back to list, and use it to iterate through the array.



                                    declare -A ADDR
                                    ADDR[192.168.1.1]="host1"
                                    ADDR[192.168.1.2]="host2"
                                    etc...

                                    KEYS=`echo ${!ADDR[@]} | tr ' ' '12' | sort | tr '12' ' '`
                                    for KEY in $KEYS; do
                                    VAL=${ADDR[$KEY]}
                                    echo "KEY=[$KEY] VAL=[$VAL]"
                                    done





                                    share|improve this answer


























                                      0












                                      0








                                      0







                                      The best way to sort a bash associative array by KEY is to NOT sort it.



                                      Instead, get the list of KEYS, sort that list as a variable, and iterate through the list. Example: Suppose you have an array of IP addresses (keys) and host names (values):



                                      Alternative:
                                      Create new list from KEYs, convert to lines, sort it, convert back to list, and use it to iterate through the array.



                                      declare -A ADDR
                                      ADDR[192.168.1.1]="host1"
                                      ADDR[192.168.1.2]="host2"
                                      etc...

                                      KEYS=`echo ${!ADDR[@]} | tr ' ' '12' | sort | tr '12' ' '`
                                      for KEY in $KEYS; do
                                      VAL=${ADDR[$KEY]}
                                      echo "KEY=[$KEY] VAL=[$VAL]"
                                      done





                                      share|improve this answer













                                      The best way to sort a bash associative array by KEY is to NOT sort it.



                                      Instead, get the list of KEYS, sort that list as a variable, and iterate through the list. Example: Suppose you have an array of IP addresses (keys) and host names (values):



                                      Alternative:
                                      Create new list from KEYs, convert to lines, sort it, convert back to list, and use it to iterate through the array.



                                      declare -A ADDR
                                      ADDR[192.168.1.1]="host1"
                                      ADDR[192.168.1.2]="host2"
                                      etc...

                                      KEYS=`echo ${!ADDR[@]} | tr ' ' '12' | sort | tr '12' ' '`
                                      for KEY in $KEYS; do
                                      VAL=${ADDR[$KEY]}
                                      echo "KEY=[$KEY] VAL=[$VAL]"
                                      done






                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered Feb 6 at 18:24









                                      mz4wheelermz4wheeler

                                      1




                                      1






























                                          draft saved

                                          draft discarded




















































                                          Thanks for contributing an answer to Unix & Linux Stack Exchange!


                                          • Please be sure to answer the question. Provide details and share your research!

                                          But avoid



                                          • Asking for help, clarification, or responding to other answers.

                                          • Making statements based on opinion; back them up with references or personal experience.


                                          To learn more, see our tips on writing great answers.




                                          draft saved


                                          draft discarded














                                          StackExchange.ready(
                                          function () {
                                          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f51998%2fwhats-the-right-way-to-sort-a-associated-array-in-bash-or-zsh%23new-answer', 'question_page');
                                          }
                                          );

                                          Post as a guest















                                          Required, but never shown





















































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown

































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown







                                          Popular posts from this blog

                                          How to reconfigure Docker Trusted Registry 2.x.x to use CEPH FS mount instead of NFS and other traditional...

                                          is 'sed' thread safe

                                          How to make a Squid Proxy server?