feat(unitproc/bkt-get_median):Add Bash function to calculate median
[BK-2020-03.git] / unitproc / bkt-get_median
1 #!/usr/bin/env bash
2
3 read_stdin() {
4 # Desc: Consumes stdin; outputs as stdout lines
5 # Input: stdin (consumes)
6 # Output: stdout (newline delimited)
7 # Example: printf "foo\nbar\n" | read_stdin
8 # Depends: GNU bash (version 5.1.16)
9 # Version: 0.0.1
10 local input_stdin output;
11
12 # Store stdin
13 if [[ -p /dev/stdin ]]; then
14 input_stdin="$(cat -)";
15 fi;
16
17 # Store as output array elements
18 ## Read in stdin
19 if [[ -n $input_stdin ]]; then
20 while read -r line; do
21 output+=("$line");
22 done < <(printf "%s\n" "$input_stdin");
23 fi;
24
25 # Print to stdout
26 printf "%s\n" "${output[@]}";
27 }; # read stdin to stdout lines
28 get_median() {
29 # Desc: Gets the median from integers or floats read from stdin
30 # Input: stdin newline-delimited integers or floats
31 # Output: stdout float
32 # Depends: GNU Coreutils 8.32 (sort), bc 1.07.1
33 # Depends: BK-2020-03: read_stdin() 0.0.1,
34 # Version: 0.0.1
35
36 # Read stdin
37 list="$(read_stdin)";
38
39 # Sort list
40 list="$(printf "%s\n" "$list" | sort -n)";
41
42 # Get list length
43 list_lc="$(printf "%s\n" "$list" | wc -l)";
44
45 # Get number of lines to trim from start and end
46 if [[ $((list_lc % 2)) -eq 0 ]]; then
47 # If even
48 trim=$(( list_lc / 2 - 1 ));
49 flag_even="true";
50 else
51 # If odd
52 trim=$(( list_lc / 2 ));
53 fi;
54
55 # Trim lines
56 list="$(printf "%s\n" "$list" | tail -n+$((trim+1)) | head -n-$((trim)) )";
57
58 # Get median
59 if [[ "$flag_even" == "true" ]]; then
60 ## Average remaining two lines
61 l1="$(printf "%s\n" "$list" | head -n1)";
62 l2="$(printf "%s\n" "$list" | tail -n1)";
63 median="$( echo "( $l1 + $l2 ) / 2" | bc -l; )";
64 else
65 ## Median is simply remmaining line
66 median="$list";
67 fi;
68
69 # Output median
70 printf "%s" "$median";
71
72 # Author: Steven Baltakatei Sandoval
73 # License: GPLv3+
74 }; # Returns median float from a list
75
76 # Test
77 shuf -i1-100 -n49 | get_median; printf "\n";
78 printf "17\n5\n11.1111\n3.141592\n2\n343.4343434343434343\n" | get_median; printf "\n";