|
23 | 23 |
|
24 | 24 | import java.util.*;
|
25 | 25 | import java.util.Map.Entry;
|
| 26 | +import java.util.Objects; |
| 27 | +import java.util.Optional; |
| 28 | +import java.util.TreeSet; |
26 | 29 | import java.util.function.*;
|
27 | 30 | import java.util.stream.Collector;
|
28 | 31 | import java.util.stream.Stream;
|
@@ -1076,4 +1079,149 @@ private static int percentileIndex(double percentile, int size) {
|
1076 | 1079 | s -> s.map(Objects::toString).orElse("")
|
1077 | 1080 | );
|
1078 | 1081 | }
|
| 1082 | + |
| 1083 | + |
| 1084 | + //CS304 Issue link: https://github.com/jOOQ/jOOL/issues/360 |
| 1085 | + |
| 1086 | + /** |
| 1087 | + * Calculate the variance of objects with mapping function from object to double value, |
| 1088 | + * with given list, size and mapping function. |
| 1089 | + * |
| 1090 | + * <p><pre> |
| 1091 | + * This function is based on the definition of standard deviation: |
| 1092 | + * First, calculate the sum of value of all objects and the average value; |
| 1093 | + * Second, calculate the sum of square of difference between each objects and average; |
| 1094 | + * Third, use sum of variance divide size to obtain variance of all objects. |
| 1095 | + * </pre> |
| 1096 | + * |
| 1097 | + * @param function mapping function from object to double value |
| 1098 | + * @param l a list containing all the objects |
| 1099 | + * @param size the size of the list in collector |
| 1100 | + * @return the variance value |
| 1101 | + * @version 1.0 |
| 1102 | + * @author Jichen Lu |
| 1103 | + * @date 2021-04-25 |
| 1104 | + */ |
| 1105 | + private static <T> double getVariance( |
| 1106 | + Function<? super T, Double> function, |
| 1107 | + ArrayList<T> l, int size) { |
| 1108 | + double sum = 0.0; |
| 1109 | + double average; |
| 1110 | + double sumVariance = 0.0; |
| 1111 | + double variance; |
| 1112 | + for (T o : l) { |
| 1113 | + double temp = function.apply(o); |
| 1114 | + sum += temp; |
| 1115 | + } |
| 1116 | + average = sum / size; |
| 1117 | + for (T o : l) { |
| 1118 | + double temp = Math.pow(function.apply(o) - average, 2); |
| 1119 | + sumVariance += temp; |
| 1120 | + } |
| 1121 | + variance = sumVariance / size; |
| 1122 | + return variance; |
| 1123 | + } |
| 1124 | + |
| 1125 | + |
| 1126 | + //CS304 Issue link: https://github.com/jOOQ/jOOL/issues/360 |
| 1127 | + |
| 1128 | + /** |
| 1129 | + * Calculate the variance of the given object collectors, |
| 1130 | + * based on the mapping function from object to double number. |
| 1131 | + * |
| 1132 | + * <p><pre> Usage of aggregation function stddevBy(): |
| 1133 | + * The mapping function is a function mapping the objects to a double value, for instance: |
| 1134 | + * {@code |
| 1135 | + * Function<Integer, Double> mapping = e -> Double.valueOf(e); |
| 1136 | + * } |
| 1137 | + * The specific usage of stddevBy is like: |
| 1138 | + * {@code |
| 1139 | + * Seq.of(1, 1, 1, 1).collect(Agg.stddevBy(mapping)); |
| 1140 | + * } |
| 1141 | + * Besides, self defined class is also allowed with mapping function: |
| 1142 | + * {@code |
| 1143 | + * Seq.of(new Node(1), new Node(1), new Node(1), new Node(1)).collect(Agg.stddevBy(mapping1)); |
| 1144 | + * } |
| 1145 | + * </pre> |
| 1146 | + * |
| 1147 | + * @param function mapping function from object to double value |
| 1148 | + * @return the stddev value |
| 1149 | + * @version 1.0 |
| 1150 | + * @author Jichen Lu |
| 1151 | + * @date 2021-04-25 |
| 1152 | + */ |
| 1153 | + public static <T> Collector<T, ?, Optional<Double>> stddevBy( |
| 1154 | + Function<? super T, |
| 1155 | + Double> function) { |
| 1156 | + return Collector.of( |
| 1157 | + (Supplier<ArrayList<T>>) ArrayList::new, |
| 1158 | + ArrayList::add, |
| 1159 | + (l1, l2) -> { |
| 1160 | + l1.addAll(l2); |
| 1161 | + return l1; |
| 1162 | + }, |
| 1163 | + l -> { |
| 1164 | + int size = l.size(); |
| 1165 | + if (size == 0) { |
| 1166 | + return Optional.empty(); |
| 1167 | + } |
| 1168 | + double variance = getVariance(function, l, size); |
| 1169 | + double stddev; |
| 1170 | + |
| 1171 | + |
| 1172 | + stddev = Math.sqrt(variance); |
| 1173 | + |
| 1174 | + return Optional.of(stddev); |
| 1175 | + } |
| 1176 | + ); |
| 1177 | + } |
| 1178 | + |
| 1179 | + |
| 1180 | + //CS304 Issue link: https://github.com/jOOQ/jOOL/issues/360 |
| 1181 | + |
| 1182 | + /** |
| 1183 | + * Calculate the variance of the given object collectors, |
| 1184 | + * based on the mapping function from object to double number. |
| 1185 | + * |
| 1186 | + * <p><pre> Usage of aggregation function varianceBy(): |
| 1187 | + * The mapping function is a function mapping the objects to a double value, for instance: |
| 1188 | + * {@code |
| 1189 | + * Function<Integer, Double> mapping = e -> Double.valueOf(e); |
| 1190 | + * } |
| 1191 | + * The specific usage of varianceBy is like: |
| 1192 | + * {@code |
| 1193 | + * Seq.of(1, 1, 1, 1).collect(Agg.varianceBy(mapping)); |
| 1194 | + * } |
| 1195 | + * Besides, self defined class is also allowed with mapping function: |
| 1196 | + * {@code |
| 1197 | + * Seq.of(new Node(1), new Node(1), new Node(1), new Node(1)).collect(Agg.varianceBy(mapping1)); |
| 1198 | + * } |
| 1199 | + * </pre> |
| 1200 | + * |
| 1201 | + * @param function mapping function from object to double value |
| 1202 | + * @return the stddev value |
| 1203 | + * @version 1.0 |
| 1204 | + * @author Jichen Lu |
| 1205 | + * @date 2021-04-25 |
| 1206 | + */ |
| 1207 | + public static <T> Collector<T, ?, Optional<Double>> varianceBy( |
| 1208 | + Function<? super T, |
| 1209 | + Double> function) { |
| 1210 | + return Collector.of( |
| 1211 | + (Supplier<ArrayList<T>>) ArrayList::new, |
| 1212 | + ArrayList::add, |
| 1213 | + (l1, l2) -> { |
| 1214 | + l1.addAll(l2); |
| 1215 | + return l1; |
| 1216 | + }, |
| 1217 | + l -> { |
| 1218 | + int size = l.size(); |
| 1219 | + if (size == 0) { |
| 1220 | + return Optional.empty(); |
| 1221 | + } |
| 1222 | + double variance = getVariance(function, l, size); |
| 1223 | + return Optional.of(variance); |
| 1224 | + } |
| 1225 | + ); |
| 1226 | + } |
1079 | 1227 | }
|
0 commit comments