-
-
Save Miha-x64/406317855c0c91bfa66bd711bf22d1b6 to your computer and use it in GitHub Desktop.
class Stats - used with Stream.collect() to find min and max
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.aquadc.util; | |
import java.util.Comparator; | |
import java.util.Objects; | |
import java.util.Optional; | |
import java.util.stream.Collector; | |
/** | |
* Stats of a stream of objects, including {@linkplain #size()}, {@linkplain #min()}, and {@linkplain #max()}. | |
* <p>This is intended to be used with {@link java.util.stream.Stream#collect}, for example</p> | |
* <pre> | |
* Stats<String> stats = stringStream.collect(sizeMinMax()); | |
* Stats<String> stringStream.collect(sizeMinMax(comparing(String::length))); | |
* </pre> | |
* <p>Original post and explanation on SO: http://stackoverflow.com/questions/41816264</p> | |
* <p>This fork: https://gist.github.com/Miha-x64/406317855c0c91bfa66bd711bf22d1b6</p> | |
* <p>License: Public Domain</p> | |
*/ | |
public final class Stats<T> { | |
private final Comparator<? super T> comparator; | |
private long size; | |
private T min; | |
private T max; | |
private Stats(Comparator<? super T> comparator) { | |
this.comparator = comparator; | |
} | |
public long size() { return size; } | |
public Optional<T> min() { return size == 0 ? Optional.empty() : Optional.of(min); } | |
public Optional<T> max() { return size == 0 ? Optional.empty() : Optional.of(max); } | |
@Override public boolean equals(Object o) { | |
if (this == o) return true; | |
if (o == null || getClass() != o.getClass()) return false; | |
Stats<?> stats = (Stats<?>) o; | |
return size == stats.size && | |
comparator.equals(stats.comparator) && | |
// with both.size == 0, min and max are gonna be uninitialized, be safe: | |
Objects.equals(min, stats.min) && | |
Objects.equals(max, stats.max); | |
} | |
@Override public int hashCode() { | |
int result = comparator.hashCode(); | |
if (size != 0) { | |
result = 31*result + Long.hashCode(size); | |
result = 31*result + min.hashCode(); | |
result = 31*result + max.hashCode(); | |
} | |
return result; | |
} | |
@Override public String toString() { | |
StringBuilder sb = new StringBuilder("Stats{"); | |
if (size == 0) { | |
sb.append("empty"); | |
} else { | |
sb.append("size=").append(size).append(", ").append("min=").append(min).append(", max=").append(max); | |
} | |
sb.append(", ").append("comparator="); | |
if (comparator instanceof Enum<?>) // Josh Bloch's singleton :'( e.g. NaturalOrderComparator | |
sb.append(comparator.getClass().getName()).append('.'); | |
sb.append(comparator); | |
return sb.append('}').toString(); | |
} | |
private void accept(T val) { | |
if (size == 0) min = max = val; | |
else if (comparator.compare(val, min) < 0) min = val; | |
else if (comparator.compare(val, max) > 0) max = val; | |
size++; | |
} | |
private Stats<T> combine(Stats<T> that) { | |
if (this.size == 0) return that; | |
else if (that.size == 0) return this; | |
else { | |
this.size += that.size; | |
if (comparator.compare(that.min, this.min) < 0) this.min = that.min; | |
if (comparator.compare(that.max, this.max) > 0) this.max = that.max; | |
return this; | |
} | |
} | |
public static <T> Collector<T, Stats<T>, Stats<T>> sizeMinMax(Comparator<? super T> comparator) { | |
return Collector.of( | |
() -> new Stats<>(comparator), Stats::accept, Stats::combine, | |
Collector.Characteristics.UNORDERED, Collector.Characteristics.IDENTITY_FINISH | |
); | |
} | |
public static <T extends Comparable<? super T>> Collector<T, Stats<T>, Stats<T>> sizeMinMax() { | |
return sizeMinMax(Comparator.naturalOrder()); | |
} | |
/*public static void main(String[] args) { | |
System.out.println(java.util.stream.Stream.<String>empty().collect(sizeMinMax())); | |
Stats<Long> stats = java.util.stream.LongStream.rangeClosed(-123, +1_000_000).boxed().parallel().collect(sizeMinMax()); | |
System.out.println(stats); | |
Comparator<Long> comparator = Comparator.<Long>naturalOrder().reversed(); | |
stats = java.util.stream.LongStream.rangeClosed(-123, +1_000_000).boxed() | |
.parallel() | |
.collect(sizeMinMax(comparator)); | |
System.out.println(stats); | |
}*/ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment