function quickSelect(arr, k, compare) {
    if (k >= arr.length) {
      throw new Error('k out of bounds');
    } // check for NaN values since these can cause an infinite while loop


    for (var i = 0; i < arr.length; i++) {
      if (isNumeric(arr[i]) && isNaN(arr[i])) {
        return arr[i]; // return NaN
      }
    }

    var from = 0;
    var to = arr.length - 1; // if from == to we reached the kth element

    while (from < to) {
      var r = from;
      var w = to;
      var pivot = arr[Math.floor(Math.random() * (to - from + 1)) + from]; // stop if the reader and writer meets

      while (r < w) {
        // arr[r] >= pivot
        if (compare(arr[r], pivot) >= 0) {
          // put the large values at the end
          var tmp = arr[w];
          arr[w] = arr[r];
          arr[r] = tmp;
          --w;
        } else {
          // the value is smaller than the pivot, skip
          ++r;
        }
      } // if we stepped up (r++) we need to step one down (arr[r] > pivot)


      if (compare(arr[r], pivot) > 0) {
        --r;
      } // the r pointer is on the end of the first k elements


      if (k <= r) {
        to = r;
      } else {
        from = r + 1;
      }
    }

    return arr[k];
  }
Quickselect algorithm.
Code adapted from:
https://blog.teamleadnet.com/2012/07/quick-select-algorithm-find-kth-element.html

@param {Array} arr
@param {Number} k
@param {Function} compare
@private