Created
September 27, 2013 07:24
-
-
Save quelgar/6725210 to your computer and use it in GitHub Desktop.
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
import java.util.*; | |
import java.util.stream.Stream; | |
/** | |
* Find the most frequently occurring item that occurs more than once. | |
* Idea from http://skipoleschris.blogspot.com.au/2010/11/functional-programming-challenge-most.html | |
*/ | |
public final class Most { | |
private static final class Accum<T> { | |
public final Optional<T> winning; | |
public final Map<T, Integer> seen; | |
public Accum(final Optional<T> winning, final Map<T, Integer> seen) { | |
this.winning = winning; | |
this.seen = seen; | |
} | |
} | |
private static <T> Accum<T> most2(final Accum<T> ac, final T x) { | |
// Java standard library does not have an immutable Map, so cheat slightly | |
final Map<T, Integer> newSeen = new HashMap<T, Integer>(ac.seen); | |
newSeen.compute(x, (k, v) -> v == null ? 1 : v + 1); | |
final int winningCount = ac.winning.map(ac.seen::get).orElse(1); | |
final int count = newSeen.get(x); | |
final Optional<T> newWinning = count > winningCount ? Optional.of(x) : ac.winning; | |
return new Accum<T>(newWinning, newSeen); | |
} | |
public static <T> Optional<T> most(final Stream<T> xs) { | |
return xs.reduce(new Accum<T>(Optional.empty(), Collections.emptyMap()), Most::most2, | |
(ac1, ac2) -> { | |
// this isn't actually used unless the reduce is run in parallel | |
// more cheating, sigh | |
final Map<T, Integer> seen = new HashMap<T, Integer>(ac1.seen); | |
for (final Map.Entry<T, Integer> e : ac2.seen.entrySet()) { | |
seen.merge(e.getKey(), e.getValue(), Integer::sum); | |
} | |
final Optional<T> winning = Optional.empty(); // TODO | |
throw new RuntimeException(); | |
// return new Accum<T>(winning, seen); | |
}).winning; | |
} | |
public static <T> String mostText(final Stream<T> xs) { | |
return most(xs).map(Object::toString).orElse("None"); | |
} | |
public static void main(final String[] args) { | |
final Stream<String> test1 = Stream.of("a", "b", "c", "a", "b", "a"); | |
final Stream<String> test2 = Stream.of("a", "b", "c"); | |
final Stream<String> test3 = Stream.of("a", "b", "a", "b"); | |
final Stream<String> test4 = Stream.of("b", "a", "b", "a"); | |
final Stream<String> test5 = Stream.empty(); | |
final Stream<Integer> test6 = Stream.of(1, 2, 3, 4, 2, 3, 3, 3, 2); | |
System.out.println(mostText(test1)); | |
System.out.println(mostText(test2)); | |
System.out.println(mostText(test3)); | |
System.out.println(mostText(test4)); | |
System.out.println(mostText(test5)); | |
System.out.println(mostText(test6)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment