feat(unitproc/bkt-get_median):Add Bash function to calculate median
authorSteven Baltakatei Sandoval <baltakatei@gmail.com>
Fri, 27 Oct 2023 11:51:04 +0000 (11:51 +0000)
committerSteven Baltakatei Sandoval <baltakatei@gmail.com>
Fri, 27 Oct 2023 11:51:04 +0000 (11:51 +0000)
- Note: Accepts integers of floats from stdin. Does no input validation.

unitproc/bkt-get_median [new file with mode: 0755]

diff --git a/unitproc/bkt-get_median b/unitproc/bkt-get_median
new file mode 100755 (executable)
index 0000000..bdf6a53
--- /dev/null
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+
+read_stdin() {
+    # Desc: Consumes stdin; outputs as stdout lines
+    # Input: stdin (consumes)
+    # Output: stdout (newline delimited)
+    # Example: printf "foo\nbar\n" | read_stdin
+    # Depends: GNU bash (version 5.1.16)
+    # Version: 0.0.1
+    local input_stdin output;
+
+    # Store stdin
+    if [[ -p /dev/stdin ]]; then
+        input_stdin="$(cat -)";
+    fi; 
+    
+    # Store as output array elements
+    ## Read in stdin
+    if [[ -n $input_stdin ]]; then
+        while read -r line; do
+            output+=("$line");
+        done < <(printf "%s\n" "$input_stdin");
+    fi;
+
+    # Print to stdout
+    printf "%s\n" "${output[@]}";
+}; # read stdin to stdout lines
+get_median() {
+    # Desc: Gets the median from integers or floats read from stdin
+    # Input:  stdin   newline-delimited integers or floats
+    # Output: stdout  float
+    # Depends: GNU Coreutils 8.32 (sort), bc 1.07.1
+    # Depends: BK-2020-03: read_stdin() 0.0.1,
+    # Version: 0.0.1
+
+    # Read stdin
+    list="$(read_stdin)";
+
+    # Sort list
+    list="$(printf "%s\n" "$list" | sort -n)";
+
+    # Get list length
+    list_lc="$(printf "%s\n" "$list" | wc -l)";
+
+    # Get number of lines to trim from start and end
+    if [[ $((list_lc % 2)) -eq 0 ]]; then
+        # If even
+        trim=$(( list_lc / 2 - 1 ));
+        flag_even="true";
+    else
+        # If odd
+        trim=$(( list_lc / 2 ));
+    fi;
+
+    # Trim lines
+    list="$(printf "%s\n" "$list" | tail -n+$((trim+1)) | head -n-$((trim)) )";
+
+    # Get median
+    if [[ "$flag_even" == "true" ]]; then
+        ## Average remaining two lines
+        l1="$(printf "%s\n" "$list" | head -n1)";
+        l2="$(printf "%s\n" "$list" | tail -n1)";
+        median="$( echo "( $l1 + $l2 ) / 2" | bc -l; )";
+    else
+        ## Median is simply remmaining line
+        median="$list";
+    fi;
+
+    # Output median
+    printf "%s" "$median";
+    
+    # Author: Steven Baltakatei Sandoval
+    # License: GPLv3+
+}; # Returns median float from a list
+
+# Test
+shuf -i1-100 -n49 | get_median; printf "\n";
+printf "17\n5\n11.1111\n3.141592\n2\n343.4343434343434343\n" | get_median; printf "\n";