Найти второе по величине значение в массиве

Найти второе по величине значение в массиве

У меня есть такой массив:

array=(1 2 7 6)

и хотели бы найти второе по величине значение, с выходом

secondGreatest=6

Есть ли способ сделать это в bash?

решение1

printf '%s\n' "${array[@]}" | sort -n | tail -2 | head -1

Вывести каждое значение массива на отдельной строке, отсортировать его, получить последние 2 значения, удалить последнее значение.

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

Установите это значение для secondGreatestпеременной.


У Гленна Джекмана было отличное замечание о повторяющихся числах, которое я не учел. Если вас интересуют только уникальные значения, вы можете использовать флаг -uсортировки:

secondGreatest=$(printf '%s\n' "${array[@]}" | sort -nu | tail -2 | head -1)

решение2

Это может сделать bash-специфичный цикл по массиву; вам нужно отслеживать наибольшее и второе по величине. Единственная другая сложная часть — быть осторожным с инициализацией этих значений; наибольшее значение инициализируется первым элементом; второе по величине значение инициализируется в первый раз, когда мы видим значение, которое меньше наибольшего значения. Впоследствии для второго по величине значения мы обновляем его только в том случае, если оно строго меньше текущего наибольшего значения:

#!/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" ]] || [[ ${array[i]} > $secondGreatest ]]; }
  then
    secondGreatest=${array[i]}
  fi
done

echo "secondGreatest = $secondGreatest"

Это все еще медленнее, чем вызов sort, но имеет дополнительное преимущество, заключающееся в выборе строго меньшего второго по величине значения среди нескольких больших значений (таких как 7и 7выше).

решение3

Это хорошая работа для dc:

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

Связанный контент