Find second largest value in array

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP












1















I have an array like this:



array=(1 2 7 6)


and would like to search for the second largest value, with the output being



secondGreatest=6


Is there any way to do this in bash?










share|improve this question

















  • 3





    What if array=(1 2 7 6 7)? What is the 2nd largest value, 6 or 7?

    – glenn jackman
    Jan 23 at 15:38















1















I have an array like this:



array=(1 2 7 6)


and would like to search for the second largest value, with the output being



secondGreatest=6


Is there any way to do this in bash?










share|improve this question

















  • 3





    What if array=(1 2 7 6 7)? What is the 2nd largest value, 6 or 7?

    – glenn jackman
    Jan 23 at 15:38













1












1








1


1






I have an array like this:



array=(1 2 7 6)


and would like to search for the second largest value, with the output being



secondGreatest=6


Is there any way to do this in bash?










share|improve this question














I have an array like this:



array=(1 2 7 6)


and would like to search for the second largest value, with the output being



secondGreatest=6


Is there any way to do this in bash?







bash bash-array






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jan 23 at 13:05









ToasterFrogsToasterFrogs

443




443







  • 3





    What if array=(1 2 7 6 7)? What is the 2nd largest value, 6 or 7?

    – glenn jackman
    Jan 23 at 15:38












  • 3





    What if array=(1 2 7 6 7)? What is the 2nd largest value, 6 or 7?

    – glenn jackman
    Jan 23 at 15:38







3




3





What if array=(1 2 7 6 7)? What is the 2nd largest value, 6 or 7?

– glenn jackman
Jan 23 at 15:38





What if array=(1 2 7 6 7)? What is the 2nd largest value, 6 or 7?

– glenn jackman
Jan 23 at 15:38










3 Answers
3






active

oldest

votes


















4














printf '%sn' "$array[@]" | sort -n | tail -2 | head -1


Print each value of the array on it's own line, sort it, get the last 2 values, remove the last value



secondGreatest=$(printf '%sn' "$array[@]" | sort -n | tail -2 | head -1)


Set that value to the secondGreatest variable.




Glenn Jackman had an excellent point about duplicate numbers that I didn't consider. If you only care about unique values you can use the -u flag of sort:



secondGreatest=$(printf '%sn' "$array[@]" | sort -nu | tail -2 | head -1)





share|improve this answer




















  • 5





    You could save one pipe if you reverse sort, so that the answer is always in second place e.g. printf '%sn' "$array[@]" | sort -rn | awk NR==2 (likely head + tail is more efficient though) or (at least with GNU Coreutils, which support the null delimiters) printf '%s' "$array[@]" | sort -rzn | cut -d '' -f2

    – steeldriver
    Jan 23 at 14:03


















4














A bash-specific loop through the array could do it; you have to keep track of the largest and second-largest. The only other tricky part is to be careful about initializing those values; the largest value is initialized to the first element; the second-largest value is initialized the first time we see a value that's smaller than the largest value. Subsequently for the second-largest value, we only update it if it's strictly less than the current largest value:



#!/bin/bash

array=(7 7 6 2 1)

if [ "$#array[@]" -lt 2 ]
then
echo Incoming array is not large enough >&2
exit 1
fi

largest=$array[0]
secondGreatest='unset'

for((i=1; i < $#array[@]; i++))
do
if [[ $array[i] > $largest ]]
then
secondGreatest=$largest
largest=$array[i]
elif (( $array[i] != $largest )) && [[ "$secondGreatest" = "unset" ]]
then
secondGreatest=$array[i]
fi
done

echo "secondGreatest = $secondGreatest"


It's still slower than calling out to sort, but it has the added benefit of picking the strictly-smaller second-largest value in the face of multiple high values (such as 7 and 7 above).






share|improve this answer






























    0














    It's a good job for dc :



    array=(1 2 7 6)
    echo $array[*] | dc -f - -e '
    [lasbdsa]sB
    [dla!>Bsc1z>A]sA
    lAx
    [secondGreatest=]nlbp'





    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%2f496213%2ffind-second-largest-value-in-array%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      4














      printf '%sn' "$array[@]" | sort -n | tail -2 | head -1


      Print each value of the array on it's own line, sort it, get the last 2 values, remove the last value



      secondGreatest=$(printf '%sn' "$array[@]" | sort -n | tail -2 | head -1)


      Set that value to the secondGreatest variable.




      Glenn Jackman had an excellent point about duplicate numbers that I didn't consider. If you only care about unique values you can use the -u flag of sort:



      secondGreatest=$(printf '%sn' "$array[@]" | sort -nu | tail -2 | head -1)





      share|improve this answer




















      • 5





        You could save one pipe if you reverse sort, so that the answer is always in second place e.g. printf '%sn' "$array[@]" | sort -rn | awk NR==2 (likely head + tail is more efficient though) or (at least with GNU Coreutils, which support the null delimiters) printf '%s' "$array[@]" | sort -rzn | cut -d '' -f2

        – steeldriver
        Jan 23 at 14:03















      4














      printf '%sn' "$array[@]" | sort -n | tail -2 | head -1


      Print each value of the array on it's own line, sort it, get the last 2 values, remove the last value



      secondGreatest=$(printf '%sn' "$array[@]" | sort -n | tail -2 | head -1)


      Set that value to the secondGreatest variable.




      Glenn Jackman had an excellent point about duplicate numbers that I didn't consider. If you only care about unique values you can use the -u flag of sort:



      secondGreatest=$(printf '%sn' "$array[@]" | sort -nu | tail -2 | head -1)





      share|improve this answer




















      • 5





        You could save one pipe if you reverse sort, so that the answer is always in second place e.g. printf '%sn' "$array[@]" | sort -rn | awk NR==2 (likely head + tail is more efficient though) or (at least with GNU Coreutils, which support the null delimiters) printf '%s' "$array[@]" | sort -rzn | cut -d '' -f2

        – steeldriver
        Jan 23 at 14:03













      4












      4








      4







      printf '%sn' "$array[@]" | sort -n | tail -2 | head -1


      Print each value of the array on it's own line, sort it, get the last 2 values, remove the last value



      secondGreatest=$(printf '%sn' "$array[@]" | sort -n | tail -2 | head -1)


      Set that value to the secondGreatest variable.




      Glenn Jackman had an excellent point about duplicate numbers that I didn't consider. If you only care about unique values you can use the -u flag of sort:



      secondGreatest=$(printf '%sn' "$array[@]" | sort -nu | tail -2 | head -1)





      share|improve this answer















      printf '%sn' "$array[@]" | sort -n | tail -2 | head -1


      Print each value of the array on it's own line, sort it, get the last 2 values, remove the last value



      secondGreatest=$(printf '%sn' "$array[@]" | sort -n | tail -2 | head -1)


      Set that value to the secondGreatest variable.




      Glenn Jackman had an excellent point about duplicate numbers that I didn't consider. If you only care about unique values you can use the -u flag of sort:



      secondGreatest=$(printf '%sn' "$array[@]" | sort -nu | tail -2 | head -1)






      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Jan 23 at 20:37

























      answered Jan 23 at 13:16









      Jesse_bJesse_b

      12.7k23067




      12.7k23067







      • 5





        You could save one pipe if you reverse sort, so that the answer is always in second place e.g. printf '%sn' "$array[@]" | sort -rn | awk NR==2 (likely head + tail is more efficient though) or (at least with GNU Coreutils, which support the null delimiters) printf '%s' "$array[@]" | sort -rzn | cut -d '' -f2

        – steeldriver
        Jan 23 at 14:03












      • 5





        You could save one pipe if you reverse sort, so that the answer is always in second place e.g. printf '%sn' "$array[@]" | sort -rn | awk NR==2 (likely head + tail is more efficient though) or (at least with GNU Coreutils, which support the null delimiters) printf '%s' "$array[@]" | sort -rzn | cut -d '' -f2

        – steeldriver
        Jan 23 at 14:03







      5




      5





      You could save one pipe if you reverse sort, so that the answer is always in second place e.g. printf '%sn' "$array[@]" | sort -rn | awk NR==2 (likely head + tail is more efficient though) or (at least with GNU Coreutils, which support the null delimiters) printf '%s' "$array[@]" | sort -rzn | cut -d '' -f2

      – steeldriver
      Jan 23 at 14:03





      You could save one pipe if you reverse sort, so that the answer is always in second place e.g. printf '%sn' "$array[@]" | sort -rn | awk NR==2 (likely head + tail is more efficient though) or (at least with GNU Coreutils, which support the null delimiters) printf '%s' "$array[@]" | sort -rzn | cut -d '' -f2

      – steeldriver
      Jan 23 at 14:03













      4














      A bash-specific loop through the array could do it; you have to keep track of the largest and second-largest. The only other tricky part is to be careful about initializing those values; the largest value is initialized to the first element; the second-largest value is initialized the first time we see a value that's smaller than the largest value. Subsequently for the second-largest value, we only update it if it's strictly less than the current largest value:



      #!/bin/bash

      array=(7 7 6 2 1)

      if [ "$#array[@]" -lt 2 ]
      then
      echo Incoming array is not large enough >&2
      exit 1
      fi

      largest=$array[0]
      secondGreatest='unset'

      for((i=1; i < $#array[@]; i++))
      do
      if [[ $array[i] > $largest ]]
      then
      secondGreatest=$largest
      largest=$array[i]
      elif (( $array[i] != $largest )) && [[ "$secondGreatest" = "unset" ]]
      then
      secondGreatest=$array[i]
      fi
      done

      echo "secondGreatest = $secondGreatest"


      It's still slower than calling out to sort, but it has the added benefit of picking the strictly-smaller second-largest value in the face of multiple high values (such as 7 and 7 above).






      share|improve this answer



























        4














        A bash-specific loop through the array could do it; you have to keep track of the largest and second-largest. The only other tricky part is to be careful about initializing those values; the largest value is initialized to the first element; the second-largest value is initialized the first time we see a value that's smaller than the largest value. Subsequently for the second-largest value, we only update it if it's strictly less than the current largest value:



        #!/bin/bash

        array=(7 7 6 2 1)

        if [ "$#array[@]" -lt 2 ]
        then
        echo Incoming array is not large enough >&2
        exit 1
        fi

        largest=$array[0]
        secondGreatest='unset'

        for((i=1; i < $#array[@]; i++))
        do
        if [[ $array[i] > $largest ]]
        then
        secondGreatest=$largest
        largest=$array[i]
        elif (( $array[i] != $largest )) && [[ "$secondGreatest" = "unset" ]]
        then
        secondGreatest=$array[i]
        fi
        done

        echo "secondGreatest = $secondGreatest"


        It's still slower than calling out to sort, but it has the added benefit of picking the strictly-smaller second-largest value in the face of multiple high values (such as 7 and 7 above).






        share|improve this answer

























          4












          4








          4







          A bash-specific loop through the array could do it; you have to keep track of the largest and second-largest. The only other tricky part is to be careful about initializing those values; the largest value is initialized to the first element; the second-largest value is initialized the first time we see a value that's smaller than the largest value. Subsequently for the second-largest value, we only update it if it's strictly less than the current largest value:



          #!/bin/bash

          array=(7 7 6 2 1)

          if [ "$#array[@]" -lt 2 ]
          then
          echo Incoming array is not large enough >&2
          exit 1
          fi

          largest=$array[0]
          secondGreatest='unset'

          for((i=1; i < $#array[@]; i++))
          do
          if [[ $array[i] > $largest ]]
          then
          secondGreatest=$largest
          largest=$array[i]
          elif (( $array[i] != $largest )) && [[ "$secondGreatest" = "unset" ]]
          then
          secondGreatest=$array[i]
          fi
          done

          echo "secondGreatest = $secondGreatest"


          It's still slower than calling out to sort, but it has the added benefit of picking the strictly-smaller second-largest value in the face of multiple high values (such as 7 and 7 above).






          share|improve this answer













          A bash-specific loop through the array could do it; you have to keep track of the largest and second-largest. The only other tricky part is to be careful about initializing those values; the largest value is initialized to the first element; the second-largest value is initialized the first time we see a value that's smaller than the largest value. Subsequently for the second-largest value, we only update it if it's strictly less than the current largest value:



          #!/bin/bash

          array=(7 7 6 2 1)

          if [ "$#array[@]" -lt 2 ]
          then
          echo Incoming array is not large enough >&2
          exit 1
          fi

          largest=$array[0]
          secondGreatest='unset'

          for((i=1; i < $#array[@]; i++))
          do
          if [[ $array[i] > $largest ]]
          then
          secondGreatest=$largest
          largest=$array[i]
          elif (( $array[i] != $largest )) && [[ "$secondGreatest" = "unset" ]]
          then
          secondGreatest=$array[i]
          fi
          done

          echo "secondGreatest = $secondGreatest"


          It's still slower than calling out to sort, but it has the added benefit of picking the strictly-smaller second-largest value in the face of multiple high values (such as 7 and 7 above).







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jan 23 at 14:38









          Jeff SchallerJeff Schaller

          41.2k1056131




          41.2k1056131





















              0














              It's a good job for dc :



              array=(1 2 7 6)
              echo $array[*] | dc -f - -e '
              [lasbdsa]sB
              [dla!>Bsc1z>A]sA
              lAx
              [secondGreatest=]nlbp'





              share|improve this answer



























                0














                It's a good job for dc :



                array=(1 2 7 6)
                echo $array[*] | dc -f - -e '
                [lasbdsa]sB
                [dla!>Bsc1z>A]sA
                lAx
                [secondGreatest=]nlbp'





                share|improve this answer

























                  0












                  0








                  0







                  It's a good job for dc :



                  array=(1 2 7 6)
                  echo $array[*] | dc -f - -e '
                  [lasbdsa]sB
                  [dla!>Bsc1z>A]sA
                  lAx
                  [secondGreatest=]nlbp'





                  share|improve this answer













                  It's a good job for dc :



                  array=(1 2 7 6)
                  echo $array[*] | dc -f - -e '
                  [lasbdsa]sB
                  [dla!>Bsc1z>A]sA
                  lAx
                  [secondGreatest=]nlbp'






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Jan 23 at 19:32









                  ctac_ctac_

                  1,4141210




                  1,4141210



























                      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%2f496213%2ffind-second-largest-value-in-array%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 check contact read email or not when send email to Individual?

                      Displaying single band from multi-band raster using QGIS

                      How many registers does an x86_64 CPU actually have?