Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions core/src/main/java/fj/Ord.java
Original file line number Diff line number Diff line change
Expand Up @@ -478,12 +478,14 @@ public static <A extends Comparable<A>> Ord<A> comparableOrd() {

/**
* An order instance that uses {@link Object#hashCode()} for computing the order and equality,
* thus objects returning the same hashCode are considered to be equals (check {@link #hashEqualsOrd()}
* for an additional check on {@link Object#equals(Object)}).
* thus objects returning the same hashCode are considered to be equals.
* This is not safe and therefore this method is deprecated.
*
* @return An order instance that is based on {@link Object#hashCode()}.
* @see #hashEqualsOrd()
*
* @deprecated As of release 4.7.
*/
@Deprecated
public static <A> Ord<A> hashOrd() {
return ord(a -> {
int aHash = a.hashCode();
Expand All @@ -495,9 +497,13 @@ public static <A> Ord<A> hashOrd() {
* An order instance that uses {@link Object#hashCode()} and {@link Object#equals} for computing
* the order and equality. First the hashCode is compared, if this is equal, objects are compared
* using {@link Object#equals}.
* WARNING: This ordering violate antisymmetry on hash collisions.
*
* @return An order instance that is based on {@link Object#hashCode()} and {@link Object#equals}.
*
* @deprecated As of release 4.7.
*/
@Deprecated
public static <A> Ord<A> hashEqualsOrd() {
return ord(a -> {
int aHash = a.hashCode();
Expand Down
29 changes: 19 additions & 10 deletions core/src/main/java/fj/data/List.java
Original file line number Diff line number Diff line change
Expand Up @@ -1299,11 +1299,15 @@ public final A mode(final Ord<A> o) {

/**
* Groups the elements of this list by a given keyFunction into a {@link TreeMap}.
* The ordering of the keys is determined by {@link fj.Ord#hashOrd()}.
* The ordering of the keys is determined by {@link fj.Ord#hashOrd()} (ie. Object#hasCode).
* This is not safe and therefore this method is deprecated.
*
* @param keyFunction The function to select the keys for the map.
* @return A TreeMap containing the keys with the accumulated list of matched elements.
*
* @deprecated As of release 4.7, use {@link #groupBy(F, Ord)}
*/
@Deprecated
public final <B> TreeMap<B, List<A>> groupBy(final F<A, B> keyFunction) {
return groupBy(keyFunction, Ord.hashOrd());
}
Expand All @@ -1322,12 +1326,16 @@ public final <B> TreeMap<B, List<A>> groupBy(final F<A, B> keyFunction, final Or
/**
* Groups the elements of this list by a given keyFunction into a {@link TreeMap} and transforms
* the matching elements with the given valueFunction. The ordering of the keys is determined by
* {@link fj.Ord#hashOrd()}.
* {@link fj.Ord#hashOrd()} (ie. Object#hasCode).
* This is not safe and therefore this method is deprecated.
*
* @param keyFunction The function to select the keys for the map.
* @param valueFunction The function to apply on each matching value.
* @return A TreeMap containing the keys with the accumulated list of matched and mapped elements.
*
* @deprecated As of release 4.7, use {@link #groupBy(F, F, Ord)}
*/
@Deprecated
public final <B, C> TreeMap<B, List<C>> groupBy(
final F<A, B> keyFunction,
final F<A, C> valueFunction) {
Expand Down Expand Up @@ -1390,14 +1398,15 @@ public final <B, C, D> TreeMap<B, D> groupBy(
final D groupingIdentity,
final F2<C, D, D> groupingAcc,
final Ord<B> keyOrd) {
return this.foldLeft((map, element) -> {
final B key = keyFunction.f(element);
final C value = valueFunction.f(element);
return map.set(key, map.get(key)
.map(existing -> groupingAcc.f(value, existing))
.orSome(groupingAcc.f(value, groupingIdentity)));
}, TreeMap.empty(keyOrd)
);
java.util.TreeMap<B, D> buffer = new java.util.TreeMap<>(keyOrd.toComparator());
foreachDoEffect(element -> {
final B key = keyFunction.f(element);
final C value = valueFunction.f(element);
buffer.put(key, buffer.containsKey(key)
? groupingAcc.f(value, buffer.get(key))
: groupingAcc.f(value, groupingIdentity));
});
return TreeMap.fromMutableMap(keyOrd, buffer);
}


Expand Down
6 changes: 3 additions & 3 deletions demo/src/main/java/fj/demo/List_groupBy.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ public static void main(final String... args) {
private static void keyDemo() {
System.out.println("KeyDemo");
final List<String> words = list("Hello", "World", "how", "are", "your", "doing");
final TreeMap<Integer, List<String>> lengthMap = words.groupBy(String::length);
final TreeMap<Integer, List<String>> lengthMap = words.groupBy(String::length, Ord.intOrd);

lengthMap.forEach(entry -> System.out.println(String.format("Words with %d chars: %s", entry._1(), entry._2())));
}

private static void keyValueDemo() {
System.out.println("KeyValueDemo");
final List<Integer> xs = list(1, 2, 3, 4, 5, 6, 7, 8, 9);
final TreeMap<Integer, List<String>> result = xs.groupBy(x -> x % 3, Integer::toBinaryString);
final TreeMap<Integer, List<String>> result = xs.groupBy(x -> x % 3, Integer::toBinaryString, Ord.intOrd);

result.forEach(entry -> System.out.println(String.format("Numbers with reminder %d are %s", entry._1(), entry._2())));
}
Expand All @@ -35,7 +35,7 @@ private static void keyValueAccDemo() {
System.out.println("KeyValueAccDemo");
final List<String> words = list("Hello", "World", "how", "are", "your", "doing");
final TreeMap<Integer, Integer> lengthCounts =
words.groupBy(String::length, Function.identity(), 0, (word, sum) -> sum + 1, Ord.hashOrd());
words.groupBy(String::length, Function.identity(), 0, (word, sum) -> sum + 1, Ord.intOrd);

lengthCounts.forEach(entry -> System.out.println(String.format("Words with %d chars: %s", entry._1(), entry._2())));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ object CheckList extends Properties("List") {
join(a)))

property("groupBy") = forAll((a: List[Int]) => {
val result = a.groupBy((x: Int) => (x % 2 == 0): lang.Boolean)
val result = a.groupBy((x: Int) => (x % 2 == 0): lang.Boolean, Ord.booleanOrd)
result.get(true).forall((xs: List[Int]) => xs.forall((x: Int) => (x % 2 == 0): lang.Boolean): lang.Boolean) &&
result.get(false).forall((xs: List[Int]) => xs.forall((x: Int) => (x % 2 != 0): lang.Boolean): lang.Boolean) &&
a.map((x: Int) => (x % 2) == 0: lang.Boolean).nub().length() == result.size()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ public Property nub() {

public Property groupBy() {
return property(arbList(arbInteger), list -> {
final TreeMap<Boolean, List<Integer>> map = list.groupBy(i -> i % 2 == 0);
final TreeMap<Boolean, List<Integer>> map = list.groupBy(i -> i % 2 == 0, Ord.booleanOrd);
final List<Integer> list1 = map.get(true).orSome(nil());
final List<Integer> list2 = map.get(false).orSome(nil());
return prop(list.length() == list1.length() + list2.length())
Expand Down