| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| Expand Up | @@ -9,6 +9,7 @@ | |
| import java.lang.reflect.Array; | ||
| import java.util.ArrayList; | ||
| import java.util.Collection; | ||
| import java.util.Collections; | ||
| import java.util.Iterator; | ||
| import java.util.LinkedHashMap; | ||
| import java.util.List; | ||
| Expand All | @@ -18,69 +19,90 @@ | |
| import java.util.OptionalInt; | ||
| import java.util.Set; | ||
| import java.util.concurrent.CompletableFuture; | ||
| import java.util.function.BiFunction; | ||
| import java.util.function.BinaryOperator; | ||
| import java.util.function.Function; | ||
| import java.util.function.Predicate; | ||
| import java.util.function.Supplier; | ||
| import java.util.stream.Collectors; | ||
| import java.util.stream.Stream; | ||
|
|
||
| import static java.util.Collections.singletonList; | ||
| import static java.util.function.Function.identity; | ||
| import static java.util.stream.Collectors.mapping; | ||
|
|
||
| @Internal | ||
| public class FpKit { | ||
|
|
||
| // | ||
| // From a list of named things, get a map of them by name, merging them according to the merge function | ||
| public static <T> Map<String, T> getByName(List<T> namedObjects, Function<T, String> nameFn, BinaryOperator<T> mergeFunc) { | ||
| return namedObjects.stream().collect(Collectors.toMap( | ||
| nameFn, | ||
| identity(), | ||
| mergeFunc, | ||
| LinkedHashMap::new) | ||
| ); | ||
| return toMap(namedObjects, nameFn, mergeFunc); | ||
| } | ||
|
|
||
| // | ||
| // From a collection of keyed things, get a map of them by key, merging them according to the merge function | ||
| public static <T, NewKey> Map<NewKey, T> toMap(Collection<T> collection, Function<T, NewKey> keyFunction, BinaryOperator<T> mergeFunc) { | ||
| Map<NewKey, T> resultMap = new LinkedHashMap<>(); | ||
| for (T obj : collection) { | ||
| NewKey key = keyFunction.apply(obj); | ||
| if (resultMap.containsKey(key)) { | ||
| T existingValue = resultMap.get(key); | ||
| T mergedValue = mergeFunc.apply(existingValue, obj); | ||
| resultMap.put(key, mergedValue); | ||
| } else { | ||
| resultMap.put(key, obj); | ||
| } | ||
| } | ||
| return resultMap; | ||
|
Comment thread
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Qualitynew common generic function - used in other places
Sorry, something went wrong.
All reactions
|
||
| } | ||
|
|
||
| // normal groupingBy but with LinkedHashMap | ||
| public static <T, NewKey> Map<NewKey, ImmutableList<T>> groupingBy(Collection<T> list, Function<T, NewKey> function) { | ||
| return list.stream().collect(Collectors.groupingBy(function, LinkedHashMap::new, mapping(Function.identity(), ImmutableList.toImmutableList()))); | ||
| return filterAndGroupingBy(list, ALWAYS_TRUE, function); | ||
| } | ||
|
|
||
| @SuppressWarnings("unchecked") | ||
| public static <T, NewKey> Map<NewKey, ImmutableList<T>> filterAndGroupingBy(Collection<T> list, | ||
| Predicate<? super T> predicate, | ||
| Function<T, NewKey> function) { | ||
| return list.stream().filter(predicate).collect(Collectors.groupingBy(function, LinkedHashMap::new, mapping(Function.identity(), ImmutableList.toImmutableList()))); | ||
| } | ||
| // | ||
| // The cleanest version of this code would have two maps, one of immutable list builders and one | ||
| // of the built immutable lists. BUt we are trying to be performant and memory efficient so | ||
| // we treat it as a map of objects and cast like its Java 4x | ||
| // | ||
|
Comment thread
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityThis comment above explains the whacky code. One less map allocation Alternative is public static <T, NewKey> Map<NewKey, ImmutableList<T>> groupingBy(Collection<T> list, Function<T, NewKey> function) {
Map<NewKey, ImmutableList.Builder<T>> tempMap = new LinkedHashMap<>();
for (T item : list) {
NewKey key = function.apply(item);
tempMap.computeIfAbsent(key, k -> ImmutableList.builder()).add(item);
}
Map<NewKey, ImmutableList<T>> resultMap = new LinkedHashMap<>();
for (Map.Entry<NewKey, ImmutableList.Builder<T>> entry : tempMap.entrySet()) {
resultMap.put(entry.getKey(), entry.getValue().build());
}
return resultMap;
}
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityNote two allocations - neater code - worse performance
Sorry, something went wrong.
All reactions
|
||
| Map<NewKey, Object> resutMap = new LinkedHashMap<>(); | ||
| for (T item : list) { | ||
| if (predicate.test(item)) { | ||
| NewKey key = function.apply(item); | ||
| // we have to use an immutable list builder as we built it out | ||
| ((ImmutableList.Builder<Object>) resutMap.computeIfAbsent(key, k -> ImmutableList.builder())) | ||
| .add(item); | ||
| } | ||
| } | ||
| if (resutMap.isEmpty()) { | ||
|
Comment thread
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityI think you meant to call it a resultMap, anyway not blocking this PR
Sorry, something went wrong.
All reactions
|
||
| return Collections.emptyMap(); | ||
| } | ||
| // Convert builders to ImmutableLists in place to avoid an extra allocation | ||
| // yes the code is yuck - but its more performant yuck! | ||
|
Comment thread
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityDo you mind if I borrow this line for the release notes?
Sorry, something went wrong.
All reactions
|
||
| resutMap.replaceAll((key, builder) -> | ||
| ((ImmutableList.Builder<Object>) builder).build()); | ||
|
|
||
| public static <T, NewKey> Map<NewKey, ImmutableList<T>> groupingBy(Stream<T> stream, Function<T, NewKey> function) { | ||
| return stream.collect(Collectors.groupingBy(function, LinkedHashMap::new, mapping(Function.identity(), ImmutableList.toImmutableList()))); | ||
| // make it the right shape - like as if generics were never invented | ||
| return (Map<NewKey, ImmutableList<T>>) (Map<?, ?>) resutMap; | ||
| } | ||
|
|
||
| public static <T, NewKey> Map<NewKey, T> groupingByUniqueKey(Collection<T> list, Function<T, NewKey> keyFunction) { | ||
| return list.stream().collect(Collectors.toMap( | ||
| keyFunction, | ||
| identity(), | ||
| throwingMerger(), | ||
| LinkedHashMap::new) | ||
| ); | ||
| public static <T, NewKey> Map<NewKey, T> toMapByUniqueKey(Collection<T> list, Function<T, NewKey> keyFunction) { | ||
| return toMap(list, keyFunction, throwingMerger()); | ||
| } | ||
|
Comment thread
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityThis was renamed from groupingByUniqueKey to toMapByUniqueKey because its NOT a group by at all. Its a toMap - it was badly named
Sorry, something went wrong.
All reactions
|
||
|
|
||
| public static <T, NewKey> Map<NewKey, T> groupingByUniqueKey(Stream<T> stream, Function<T, NewKey> keyFunction) { | ||
| return stream.collect(Collectors.toMap( | ||
| keyFunction, | ||
| identity(), | ||
| throwingMerger(), | ||
| LinkedHashMap::new) | ||
| ); | ||
| } | ||
|
Comment thread
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Qualitynever used - so I removed it - one less stream thing to port
Sorry, something went wrong.
All reactions
|
||
|
|
||
| private static final Predicate<Object> ALWAYS_TRUE = o -> true; | ||
|
|
||
| private static final BinaryOperator<Object> THROWING_MERGER_SINGLETON = (u, v) -> { | ||
| throw new IllegalStateException(String.format("Duplicate key %s", u)); | ||
| }; | ||
|
|
||
|
|
||
| private static <T> BinaryOperator<T> throwingMerger() { | ||
| return (u, v) -> { | ||
| throw new IllegalStateException(String.format("Duplicate key %s", u)); | ||
| }; | ||
| //noinspection unchecked | ||
| return (BinaryOperator<T>) THROWING_MERGER_SINGLETON; | ||
| } | ||
|
|
||
|
|
||
| Expand Down Expand Up | @@ -240,11 +262,6 @@ public static <T> List<T> valuesToList(Map<?, T> map) { | |
| return new ArrayList<>(map.values()); | ||
| } | ||
|
|
||
| public static <K, V, U> List<U> mapEntries(Map<K, V> map, BiFunction<K, V, U> function) { | ||
| return map.entrySet().stream().map(entry -> function.apply(entry.getKey(), entry.getValue())).collect(Collectors.toList()); | ||
| } | ||
|
Comment thread
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Qualitynever used so I removed it - one less stream thing to port
Sorry, something went wrong.
All reactions
|
||
|
|
||
|
|
||
| public static <T> List<List<T>> transposeMatrix(List<? extends List<T>> matrix) { | ||
| int rowCount = matrix.size(); | ||
| int colCount = matrix.get(0).size(); | ||
| Expand All | @@ -261,21 +278,13 @@ public static <T> List<List<T>> transposeMatrix(List<? extends List<T>> matrix) | |
| return result; | ||
| } | ||
|
|
||
| public static <T> CompletableFuture<List<T>> flatList(CompletableFuture<List<List<T>>> cf) { | ||
| return cf.thenApply(FpKit::flatList); | ||
| } | ||
|
Comment thread
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Qualitynever used - no need to port it
Sorry, something went wrong.
All reactions
|
||
|
|
||
| public static <T> List<T> flatList(Collection<List<T>> listLists) { | ||
| return listLists.stream() | ||
| .flatMap(List::stream) | ||
| .collect(ImmutableList.toImmutableList()); | ||
| } | ||
|
Comment thread
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Qualitynever used - no need to port it
Sorry, something went wrong.
All reactions
|
||
|
|
||
| public static <T> Optional<T> findOne(Collection<T> list, Predicate<T> filter) { | ||
| return list | ||
| .stream() | ||
| .filter(filter) | ||
| .findFirst(); | ||
| for (T t : list) { | ||
| if (filter.test(t)) { | ||
| return Optional.of(t); | ||
| } | ||
| } | ||
| return Optional.empty(); | ||
| } | ||
|
|
||
| public static <T> T findOneOrNull(List<T> list, Predicate<T> filter) { | ||
| Expand All | @@ -292,10 +301,13 @@ public static <T> int findIndex(List<T> list, Predicate<T> filter) { | |
| } | ||
|
|
||
| public static <T> List<T> filterList(Collection<T> list, Predicate<T> filter) { | ||
| return list | ||
| .stream() | ||
| .filter(filter) | ||
| .collect(Collectors.toList()); | ||
| List<T> result = new ArrayList<>(); | ||
| for (T t : list) { | ||
| if (filter.test(t)) { | ||
| result.add(t); | ||
| } | ||
| } | ||
| return result; | ||
| } | ||
|
|
||
| public static <T> Set<T> filterSet(Collection<T> input, Predicate<T> filter) { | ||
| Expand Down Expand Up | @@ -352,9 +364,10 @@ public static <T> Supplier<T> interThreadMemoize(Supplier<T> delegate) { | |
| /** | ||
| * Faster set intersection. | ||
| * | ||
| * @param <T> for two | ||
| * @param <T> for two | ||
| * @param set1 first set | ||
| * @param set2 second set | ||
| * | ||
| * @return intersection set | ||
| */ | ||
| public static <T> Set<T> intersection(Set<T> set1, Set<T> set2) { | ||
| Expand Down | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| package graphql.util | ||
|
|
||
|
|
||
| import com.google.common.collect.ImmutableList | ||
| import spock.lang.Specification | ||
|
|
||
| import java.util.function.Supplier | ||
| Expand Down Expand Up | @@ -98,6 +98,100 @@ class FpKitTest extends Specification { | |
| l == ["Parrot"] | ||
| } | ||
|
|
||
| class Person { | ||
|
Comment thread
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Qualityhey look - TESTS! We never had very many tests for FpKit So I I write them first - then changed the implementation TDD!!!
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityNoice
Sorry, something went wrong.
All reactions
|
||
| String name | ||
| String city | ||
|
|
||
| Person(String name) { | ||
| this.name = name | ||
| } | ||
|
|
||
| Person(String name, String city) { | ||
| this.name = name | ||
| this.city = city | ||
| } | ||
|
|
||
| String getName() { | ||
| return name | ||
| } | ||
|
|
||
| String getCity() { | ||
| return city | ||
| } | ||
| } | ||
|
|
||
| def a = new Person("a", "New York") | ||
| def b = new Person("b", "New York") | ||
| def c1 = new Person("c", "Sydney") | ||
| def c2 = new Person("c", "London") | ||
|
|
||
| def "getByName tests"() { | ||
|
|
||
| when: | ||
| def map = FpKit.getByName([a, b, c1, c2], { it -> it.getName() }) | ||
| then: | ||
| map == ["a": a, "b": b, c: c1] | ||
|
|
||
| when: | ||
| map = FpKit.getByName([a, b, c1, c2], { it -> it.getName() }, { it1, it2 -> it2 }) | ||
| then: | ||
| map == ["a": a, "b": b, c: c2] | ||
| } | ||
|
|
||
| def "groupingBy tests"() { | ||
|
|
||
| when: | ||
| Map<String, ImmutableList<Person>> map = FpKit.groupingBy([a, b, c1, c2], { it -> it.getCity() }) | ||
| then: | ||
| map == ["New York": [a, b], "Sydney": [c1], "London": [c2]] | ||
|
|
||
| when: | ||
| map = FpKit.filterAndGroupingBy([a, b, c1, c2], { it -> it != c1 }, { it -> it.getCity() }) | ||
| then: | ||
| map == ["New York": [a, b], "London": [c2]] | ||
|
|
||
| } | ||
|
|
||
| def "toMapByUniqueKey works"() { | ||
|
|
||
| when: | ||
| Map<String, Person> map = FpKit.toMapByUniqueKey([a, b, c1], { it -> it.getName() }) | ||
| then: | ||
| map == ["a": a, "b": b, "c": c1] | ||
|
|
||
| when: | ||
| FpKit.toMapByUniqueKey([a, b, c1, c2], { it -> it.getName() }) | ||
| then: | ||
| def e = thrown(IllegalStateException.class) | ||
| e.message.contains("Duplicate key") | ||
| } | ||
|
|
||
| def "findOne test"() { | ||
| when: | ||
| def opt = FpKit.findOne([a, b, c1, c2], { it -> it.getName() == "c" }) | ||
| then: | ||
| opt.isPresent() | ||
| opt.get() == c1 | ||
|
|
||
| when: | ||
| opt = FpKit.findOne([a, b, c1, c2], { it -> it.getName() == "d" }) | ||
| then: | ||
| opt.isEmpty() | ||
|
|
||
| when: | ||
| opt = FpKit.findOne([a, b, c1, c2], { it -> it.getName() == "a" }) | ||
| then: | ||
| opt.isPresent() | ||
| opt.get() == a | ||
| } | ||
|
|
||
| def "filterList works"() { | ||
| when: | ||
| def list = FpKit.filterList([a, b, c1, c2], { it -> it.getName() == "c" }) | ||
| then: | ||
| list == [c1, c2] | ||
| } | ||
|
|
||
| def "set intersection works"() { | ||
| def set1 = ["A","B","C"] as Set | ||
| def set2 = ["A","C","D"] as Set | ||
| Expand Down | ||
| Back | FazBrowse Home | New Git URL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityMake it one less statement by looking up the value and save it one call
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityTechnically not the right semantics in a general sense - sure there could be non
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.