Skip to content

Commit 0359cb5

Browse files
committed
[jOOQ#151] Refactored REGR_SXY() and COVAR_POP(), and implement more functional handling of tuples of optionals
1 parent 0052689 commit 0359cb5

File tree

4 files changed

+78
-44
lines changed

4 files changed

+78
-44
lines changed

jOOL-java-8/src/main/java/org/jooq/lambda/Agg.java

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@
3030
import java.util.stream.Collector;
3131
import java.util.stream.Stream;
3232

33+
import org.jooq.lambda.function.Function2;
34+
import org.jooq.lambda.function.Function3;
3335
import org.jooq.lambda.tuple.Tuple2;
36+
import org.jooq.lambda.tuple.Tuple3;
3437

3538
/**
3639
* A set of additional {@link Collector} implementations.
@@ -1084,16 +1087,24 @@ private static <T> double variance0(List<T> l, ToDoubleFunction<? super T> funct
10841087
* Get a {@link Collector} that calculates the <code>COVAR_POP()</code> function.
10851088
*/
10861089
public static <T> Collector<T, ?, Optional<Double>> covarianceDouble(ToDoubleFunction<? super T> functionX, ToDoubleFunction<? super T> functionY) {
1087-
return collectingAndThen(toList(), l -> {
1090+
return collectingAndThen(toList(), covarianceFinisher(functionX, functionY, Agg::avg0));
1091+
}
1092+
1093+
private static <T> Function<List<T>, Optional<Double>> covarianceFinisher(
1094+
ToDoubleFunction<? super T> functionX,
1095+
ToDoubleFunction<? super T> functionY,
1096+
BiFunction<List<T>, ToDoubleFunction<? super T>, Double> sumOrAvg
1097+
) {
1098+
return l -> {
10881099
if (l.isEmpty())
10891100
return Optional.empty();
10901101
else if (l.size() == 1)
10911102
return Optional.of(0.0);
10921103

10931104
double avgX = avg0(l, functionX);
10941105
double avgY = avg0(l, functionY);
1095-
return Optional.of(avg0(l, t -> (functionX.applyAsDouble(t) - avgX) * (functionY.applyAsDouble(t) - avgY)));
1096-
});
1106+
return Optional.of(sumOrAvg.apply(l, t -> (functionX.applyAsDouble(t) - avgX) * (functionY.applyAsDouble(t) - avgY)));
1107+
};
10971108
}
10981109

10991110
/**
@@ -1113,7 +1124,7 @@ else if (l.size() == 1)
11131124
stddevDouble(functionX),
11141125
stddevDouble(functionY)
11151126
),
1116-
t -> !t.v1.isPresent() || t.v2.orElse(0.0) == 0.0 || t.v3.orElse(0.0) == 0.0 ? Optional.empty() : Optional.of(t.v1.get() / (t.v2.get() * t.v3.get()))
1127+
t -> mapAll(t, (v1, v2, v3) -> v2 == 0.0 || v3 == 0.0 ? null : v1 / (v2 * v3))
11171128
);
11181129
}
11191130

@@ -1196,13 +1207,8 @@ else if (l.size() == 1)
11961207
* Get a {@link Collector} that calculates the <code>REGR_SXY()</code> function.
11971208
*/
11981209
public static <T> Collector<T, ?, Optional<Double>> regrSxyDouble(ToDoubleFunction<? super T> functionX, ToDoubleFunction<? super T> functionY) {
1199-
return collectingAndThen(
1200-
collectors(
1201-
regrCount(functionX, functionY),
1202-
covarianceDouble(functionX, functionY)
1203-
),
1204-
t -> t.v2.map(v2 -> t.v1 * v2)
1205-
);
1210+
// REGR_SXY() is like COVAR_POP(), but using SUM() instead of AVG() at the end
1211+
return collectingAndThen(toList(), covarianceFinisher(functionX, functionY, Agg::sum0));
12061212
}
12071213

12081214
/**
@@ -1241,7 +1247,7 @@ else if (l.size() == 1)
12411247
covarianceDouble(functionX, functionY),
12421248
varianceDouble(functionY)
12431249
),
1244-
t -> !t.v1.isPresent() || t.v2.orElse(0.0) == 0.0 ? Optional.empty() : Optional.of(t.v1.get() / t.v2.get())
1250+
t -> mapAll(t, (v1, v2) -> v2 == 0.0 ? null : v1 / v2)
12451251
);
12461252
}
12471253

@@ -1262,7 +1268,7 @@ else if (l.size() == 1)
12621268
regrSlopeDouble(functionX, functionY),
12631269
regrAvgXDouble(functionX, functionY)
12641270
),
1265-
t -> !t.v1.isPresent() || !t.v2.isPresent() || !t.v3.isPresent() ? Optional.empty() : Optional.of(t.v1.get() - t.v2.get() * t.v3.get())
1271+
t -> mapAll(t, (v1, v2, v3) -> v1 - v2 * v3)
12661272
);
12671273
}
12681274

@@ -1283,23 +1289,21 @@ else if (l.size() == 1)
12831289
varianceDouble(functionX),
12841290
correlationDouble(functionX, functionY)
12851291
),
1286-
t -> !t.v1.isPresent() || !t.v2.isPresent()
1287-
? Optional.empty()
1288-
: t.v1.get() == 0.0
1289-
? Optional.empty()
1290-
: t.v2.get() == 0.0
1291-
? Optional.of(1.0)
1292-
: t.v3.map(v3 -> Math.pow(v3, 2))
1292+
t -> mapAll(t, (v1, v2, v3) -> v1 == 0.0 ? null : v2 == 0.0 ? 1.0 : Math.pow(v3, 2))
12931293
);
12941294
}
12951295

1296-
private static <T> double avg0(List<T> list, ToDoubleFunction<? super T> function) {
1296+
private static <T> double sum0(List<T> list, ToDoubleFunction<? super T> function) {
12971297
double result = 0.0;
12981298

12991299
for (T t : list)
13001300
result += function.applyAsDouble(t);
13011301

1302-
return result / list.size();
1302+
return result;
1303+
}
1304+
1305+
private static <T> double avg0(List<T> list, ToDoubleFunction<? super T> function) {
1306+
return sum0(list, function) / list.size();
13031307
}
13041308

13051309
/**
@@ -1341,4 +1345,12 @@ private static <T> double avg0(List<T> list, ToDoubleFunction<? super T> functio
13411345
s -> s.map(Objects::toString).orElse("")
13421346
);
13431347
}
1348+
1349+
private static <T1, T2, R> Optional<R> mapAll(Tuple2<Optional<T1>, Optional<T2>> tuple, Function2<T1, T2, R> function) {
1350+
return tuple.v1.flatMap(v1 -> tuple.v2.map(v2 -> function.apply(v1, v2)));
1351+
}
1352+
1353+
private static <T1, T2, T3, R> Optional<R> mapAll(Tuple3<Optional<T1>, Optional<T2>, Optional<T3>> tuple, Function3<T1, T2, T3, R> function) {
1354+
return tuple.v1.flatMap(v1 -> tuple.v2.flatMap(v2 -> tuple.v3.map(v3 -> function.apply(v1, v2, v3))));
1355+
}
13441356
}

jOOL-java-8/src/main/java/org/jooq/lambda/tuple/Tuples.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
*/
1616
package org.jooq.lambda.tuple;
1717

18+
import org.jooq.lambda.function.Function2;
19+
import org.jooq.lambda.function.Function3;
20+
21+
import java.util.Optional;
22+
1823
/**
1924
* @author Lukas Eder
2025
*/

jOOL/src/main/java/org/jooq/lambda/Agg.java

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@
3030
import java.util.stream.Collector;
3131
import java.util.stream.Stream;
3232

33+
import org.jooq.lambda.function.Function2;
34+
import org.jooq.lambda.function.Function3;
3335
import org.jooq.lambda.tuple.Tuple2;
36+
import org.jooq.lambda.tuple.Tuple3;
3437

3538
/**
3639
* A set of additional {@link Collector} implementations.
@@ -1084,16 +1087,24 @@ private static <T> double variance0(List<T> l, ToDoubleFunction<? super T> funct
10841087
* Get a {@link Collector} that calculates the <code>COVAR_POP()</code> function.
10851088
*/
10861089
public static <T> Collector<T, ?, Optional<Double>> covarianceDouble(ToDoubleFunction<? super T> functionX, ToDoubleFunction<? super T> functionY) {
1087-
return collectingAndThen(toList(), l -> {
1090+
return collectingAndThen(toList(), covarianceFinisher(functionX, functionY, Agg::avg0));
1091+
}
1092+
1093+
private static <T> Function<List<T>, Optional<Double>> covarianceFinisher(
1094+
ToDoubleFunction<? super T> functionX,
1095+
ToDoubleFunction<? super T> functionY,
1096+
BiFunction<List<T>, ToDoubleFunction<? super T>, Double> sumOrAvg
1097+
) {
1098+
return l -> {
10881099
if (l.isEmpty())
10891100
return Optional.empty();
10901101
else if (l.size() == 1)
10911102
return Optional.of(0.0);
10921103

10931104
double avgX = avg0(l, functionX);
10941105
double avgY = avg0(l, functionY);
1095-
return Optional.of(avg0(l, t -> (functionX.applyAsDouble(t) - avgX) * (functionY.applyAsDouble(t) - avgY)));
1096-
});
1106+
return Optional.of(sumOrAvg.apply(l, t -> (functionX.applyAsDouble(t) - avgX) * (functionY.applyAsDouble(t) - avgY)));
1107+
};
10971108
}
10981109

10991110
/**
@@ -1113,7 +1124,7 @@ else if (l.size() == 1)
11131124
stddevDouble(functionX),
11141125
stddevDouble(functionY)
11151126
),
1116-
t -> !t.v1.isPresent() || t.v2.orElse(0.0) == 0.0 || t.v3.orElse(0.0) == 0.0 ? Optional.empty() : Optional.of(t.v1.get() / (t.v2.get() * t.v3.get()))
1127+
t -> mapAll(t, (v1, v2, v3) -> v2 == 0.0 || v3 == 0.0 ? null : v1 / (v2 * v3))
11171128
);
11181129
}
11191130

@@ -1196,13 +1207,8 @@ else if (l.size() == 1)
11961207
* Get a {@link Collector} that calculates the <code>REGR_SXY()</code> function.
11971208
*/
11981209
public static <T> Collector<T, ?, Optional<Double>> regrSxyDouble(ToDoubleFunction<? super T> functionX, ToDoubleFunction<? super T> functionY) {
1199-
return collectingAndThen(
1200-
collectors(
1201-
regrCount(functionX, functionY),
1202-
covarianceDouble(functionX, functionY)
1203-
),
1204-
t -> t.v2.map(v2 -> t.v1 * v2)
1205-
);
1210+
// REGR_SXY() is like COVAR_POP(), but using SUM() instead of AVG() at the end
1211+
return collectingAndThen(toList(), covarianceFinisher(functionX, functionY, Agg::sum0));
12061212
}
12071213

12081214
/**
@@ -1241,7 +1247,7 @@ else if (l.size() == 1)
12411247
covarianceDouble(functionX, functionY),
12421248
varianceDouble(functionY)
12431249
),
1244-
t -> !t.v1.isPresent() || t.v2.orElse(0.0) == 0.0 ? Optional.empty() : Optional.of(t.v1.get() / t.v2.get())
1250+
t -> mapAll(t, (v1, v2) -> v2 == 0.0 ? null : v1 / v2)
12451251
);
12461252
}
12471253

@@ -1262,7 +1268,7 @@ else if (l.size() == 1)
12621268
regrSlopeDouble(functionX, functionY),
12631269
regrAvgXDouble(functionX, functionY)
12641270
),
1265-
t -> !t.v1.isPresent() || !t.v2.isPresent() || !t.v3.isPresent() ? Optional.empty() : Optional.of(t.v1.get() - t.v2.get() * t.v3.get())
1271+
t -> mapAll(t, (v1, v2, v3) -> v1 - v2 * v3)
12661272
);
12671273
}
12681274

@@ -1283,23 +1289,21 @@ else if (l.size() == 1)
12831289
varianceDouble(functionX),
12841290
correlationDouble(functionX, functionY)
12851291
),
1286-
t -> !t.v1.isPresent() || !t.v2.isPresent()
1287-
? Optional.empty()
1288-
: t.v1.get() == 0.0
1289-
? Optional.empty()
1290-
: t.v2.get() == 0.0
1291-
? Optional.of(1.0)
1292-
: t.v3.map(v3 -> Math.pow(v3, 2))
1292+
t -> mapAll(t, (v1, v2, v3) -> v1 == 0.0 ? null : v2 == 0.0 ? 1.0 : Math.pow(v3, 2))
12931293
);
12941294
}
12951295

1296-
private static <T> double avg0(List<T> list, ToDoubleFunction<? super T> function) {
1296+
private static <T> double sum0(List<T> list, ToDoubleFunction<? super T> function) {
12971297
double result = 0.0;
12981298

12991299
for (T t : list)
13001300
result += function.applyAsDouble(t);
13011301

1302-
return result / list.size();
1302+
return result;
1303+
}
1304+
1305+
private static <T> double avg0(List<T> list, ToDoubleFunction<? super T> function) {
1306+
return sum0(list, function) / list.size();
13031307
}
13041308

13051309
/**
@@ -1341,4 +1345,12 @@ private static <T> double avg0(List<T> list, ToDoubleFunction<? super T> functio
13411345
s -> s.map(Objects::toString).orElse("")
13421346
);
13431347
}
1348+
1349+
private static <T1, T2, R> Optional<R> mapAll(Tuple2<Optional<T1>, Optional<T2>> tuple, Function2<T1, T2, R> function) {
1350+
return tuple.v1.flatMap(v1 -> tuple.v2.map(v2 -> function.apply(v1, v2)));
1351+
}
1352+
1353+
private static <T1, T2, T3, R> Optional<R> mapAll(Tuple3<Optional<T1>, Optional<T2>, Optional<T3>> tuple, Function3<T1, T2, T3, R> function) {
1354+
return tuple.v1.flatMap(v1 -> tuple.v2.flatMap(v2 -> tuple.v3.map(v3 -> function.apply(v1, v2, v3))));
1355+
}
13441356
}

jOOL/src/main/java/org/jooq/lambda/tuple/Tuples.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
*/
1616
package org.jooq.lambda.tuple;
1717

18+
import org.jooq.lambda.function.Function2;
19+
import org.jooq.lambda.function.Function3;
20+
21+
import java.util.Optional;
22+
1823
/**
1924
* @author Lukas Eder
2025
*/

0 commit comments

Comments
 (0)