Get a {@link Collector} that calculates the derived <code>MEDIAN()</code> function given a specific ordering.
772162
public static <T, U> Collector<T, ?, Optional<T>> medianBy(Function<? super T, ? extends U> function, Comparator<? super U> comparator) {
        return percentileBy(0.5, function, comparator);
    }
178222
public static double median(AssociativeArray2D survivalFunction) {
        Double ApointTi = null;
        Double BpointTi = null;
        
        int n = survivalFunction.size();
        if(n==0) {
            throw new IllegalArgumentException("The provided collection can't be empty.");
        } 
        
        for(Map.Entry<Object, AssociativeArray> entry : survivalFunction.entrySet()) {
            Object ti = entry.getKey();
            AssociativeArray row = entry.getValue();
            
            Double Sti = row.getDouble("Sti");
            
            if(Sti==null) {
                continue; //skip censored
            }
            
            Double point = Double.valueOf(ti.toString());
            if(Math.abs(Sti-0.5) < 0.0000001) {
                return point; //we found extactly the point
            }
            else if(Sti>0.5) {
                ApointTi=point; //keep the point just before the 0.5 probability
            }
            else {
                BpointTi=point; //keep the first point after the 0.5 probability and exit loop
                break;
            }
        }
        
        if(n==1) {
            return (ApointTi!=null)?ApointTi:BpointTi;
        }
        else if(ApointTi == null || BpointTi == null) {
            throw new IllegalArgumentException("Invalid A and B points."); //we should never get here
        }
        
        double ApointTiValue = TypeInference.toDouble(survivalFunction.get2d(ApointTi.toString(), "Sti"));
        double BpointTiValue = TypeInference.toDouble(survivalFunction.get2d(BpointTi.toString(), "Sti"));
        double median=BpointTi-(BpointTiValue-0.5)*(BpointTi-ApointTi)/(BpointTiValue-ApointTiValue);

        return median;
    }
183755
public static <T extends Comparable<? super T>> Collector<T, ?, Optional<T>> min() {
        return minBy(t -> t, naturalOrder());
    }
51469
public static <T extends Comparable<? super T>> Collector<T, ?, Optional<Double>> percentRank(T value) {
        return percentRankBy(value, t -> t, naturalOrder());
    }
545420
public static <T> Collector<T, ?, Optional<T>> mode() {
        return mode0(seq -> seq.maxBy(t -> t.v2).map(t -> t.v1));
    }
1328008
public static <T> Collector<T, ?, Optional<T>> max(Comparator<? super T> comparator) {
        return maxBy(t -> t, comparator);
    }
1342385
public static <T extends Comparable<? super T>> Collector<T, ?, Optional<Long>> rank(T value) {
        return rankBy(value, t -> t, naturalOrder());
    }
41079
public static <T> Collector<T, ?, Optional<Long>> denseRank(T value, Comparator<? super T> comparator) {
        return denseRankBy(value, t -> t, comparator);
    }
878994
public static <T, U> Collector<T, ?, Optional<U>> percentile(double percentile, Function<? super T, ? extends U> function, Comparator<? super U> comparator) {
        return collectingAndThen(percentileBy(percentile, function, comparator), t -> t.map(function));
    }
226790
public static <C extends Comparable<? super C>>
	Collector<C, ?, ParetoFront<C>> toParetoFront() {
		return toParetoFront(Comparator.naturalOrder());
	}
960361
public static <T> Collector<T, ArrayList<List<T>>, Stream<List<T>>> inNumBatches(int numBatches) {
        // Keep the position separate from the possible threads to enable parallel
        // collection.
        AtomicInteger nextPos = new AtomicInteger(0);
        AtomicInteger numTotal = new AtomicInteger(0);
        return Collector.of(// instantiation
                            () -> {
                                ArrayList<List<T>> batches = new ArrayList<>(numBatches);
                                for (int i = 0; i < numBatches; ++i) {
                                    batches.add(new ArrayList<>());
                                }
                                return batches;
                            },
                            // accumulator
                            (batches, item) -> {
                                int pos = nextPos.getAndUpdate(i -> (++i) % numBatches);
                                batches.get(pos).add(item);
                                numTotal.incrementAndGet();
                            },
                            // combiner
                            (a, b) -> {
                                // Merge the two lists so the batches matches the order
                                // of the non-parallel inBatchesOf with (a1..an) + (b1..bn)
                                // as the set of items. It's not extremely efficient, but
                                // works fine as this is not optimized for parallel streams.
                                for (int i = 0; i < numBatches; ++i) {
                                    List<T> al = a.get(i);
                                    List<T> bl = b.get(i);
                                    al.addAll(bl);
                                }
                                return a;
                            },
                            // finalizer
                            batches -> {
                                if (numTotal.get() < numBatches) {
                                    return batches.subList(0, numTotal.get()).stream();
                                }
                                return batches.stream();
                            });
    }
125090
@NotNull
    public static <T> Collector<T, ?, Long> counting() {
        return summingLong(new ToLongFunction<T>() {

            @Override
            public long applyAsLong(T t) {
                return 1L;
            }
        });
    }
172329
public static <T, U> Collector<T, ?, Optional<U>> max(Function<? super T, ? extends U> function, Comparator<? super U> comparator) {
        return collectingAndThen(maxBy(function, comparator), t -> t.map(function));
    }
366420
public static <T, U> Collector<T, ?, Long> countDistinctBy(Function<? super T, ? extends U> function) {
        return Collector.of(
            () -> new HashSet<U>(),
            (s, v) -> s.add(function.apply(v)),
            (s1, s2) -> {
                s1.addAll(s2);
                return s1;
            },
            s -> (long) s.size()
        );
    }
210269
public static <T extends Offset<T>> Ordering<OffsetRange<T>> byEarlierStartEarlierEndOrdering() {
    return Ordering.<T>natural().onResultOf(OffsetRange.<T>toStartInclusiveFunction())
        .compound(Ordering.<T>natural().onResultOf(OffsetRange.<T>toEndInclusiveFunction()));
  }
312595
public static <T, U extends Comparable<? super U>> Collector<T, ?, Optional<Double>> percentRankBy(U value, Function<? super T, ? extends U> function) {
        return percentRankBy(value, function, naturalOrder());
    }
865337
def median(items):
    """"""
    items.sort()
    k = len(items)//2
    if len(items) % 2 == 0:
        return (items[k] + items[k - 1]) / 2
    else:
        return items[k]