Search code examples
bashmedian

Get median of unsorted array in one line of BASH


I haven't been able to find any simple implementations for finding the median of an array. How can do do this is bash without reinventing the wheel?

If currently using this:

median() {
  arr=$1
  nel=${#arr[@]}
  if (( $nel % 2 == 1 )); then     # Odd number of elements
    val="${arr[ $(($nel/2)) ]}"
  else                            # Even number of elements
    val="$(( ( arr[$((nel/2))] + arr[$((nel/2-1))] ) / 2 ))"
  fi
  printf "%d\n" "$val"
}

For some reason I still can't figure out, it's returning incorrect values, and it seems overly complicated for something so simple. I feel like there has to be a way to do this in one line.


Solution

  • I think you want something like this:

    #!/bin/bash
    median() {
      arr=($(printf '%d\n' "${@}" | sort -n))
      nel=${#arr[@]}
      if (( $nel % 2 == 1 )); then     # Odd number of elements
        val="${arr[ $(($nel/2)) ]}"
      else                            # Even number of elements
        (( j=nel/2 ))
        (( k=j-1 ))
        (( val=(${arr[j]} + ${arr[k]})/2 ))
      fi
      echo $val
    }
    
    median 1
    median 2 50 1
    median 1000 1 40 50
    

    Sample Output

    1
    2
    45