对多字段对象进行排序和分组

时间:2018-09-04 17:25:30

标签: java collections java-stream

我有List<MyObjects>,其中包含4个字段:

String fieldText;
double fieldDoubleOne;
double fieldDoubleTwo;
double fieldDoubleThree;

最好的(Java-8)方式是收集和打印列表,并根据Average(fieldDoubleOne)进行排序,以便控制台输出类似于: fieldText→平均值(fieldDoubleTwo)→平均值(fieldDoubleTwo)→平均值(fieldDoubleThree) 假定所有领域的公众获取者。对于一个双字段,我有from my previous question

Map<String, List<MyObject>> groupByFieldText = myObjectList.stream().collect(groupingBy(MyObject::getFieldText));
Map<String, Double> averageMap =   groupByFieldText.entrySet().stream()
        .map(e -> new AbstractMap.SimpleEntry<>(e.getKey(),
                e.getValue().stream()
                        .mapToDouble(d -> d.getDoubleOne()).average()
                        .orElse(0d)))
        .sorted(Comparator.comparingDouble(Map.Entry::getValue))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                (v1, v2) -> v1, LinkedHashMap::new));
averageMap.entrySet().stream().sorted(Comparator.comparingDouble((Map.Entry::getValue)))
        .forEach(System.out::println);

1 个答案:

答案 0 :(得分:0)

您只需要对条目进行排序,而不是像这样将其值映射到double

Map<String, List<MyObject>> sortedByAverageOne = groupByFieldText.entrySet().stream()
        .sorted(Comparator.comparingDouble(e -> average(e, MyObject::getDoubleOne)))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                (v1, v2) -> v1, LinkedHashMap::new));

请注意,如果您有很多条目,则效率不高,因为它会调用average进行每次比较。

然后,在具有排序后的地图的情况下,按以下方式打印它:

sortedByAverageOne.entrySet().stream()
        .map(e -> String.format(
                "%s → %f → %f → %f",
                e.getKey(),
                average(e, MyObject::getDoubleOne),
                average(e, MyObject::getDoubleTwo),
                average(e, MyObject::getDoubleThree)
        ))
        .forEach(System.out::println);

最后,average定义为:

private static double average(Map.Entry<String, List<MyObject>> entry, ToDoubleFunction<MyObject> getter) {
    return average(entry.getValue(), getter);
}

private static double average(List<MyObject> list, ToDoubleFunction<MyObject> getter) {
    return list.stream().mapToDouble(getter).average().orElse(0);
}