对groupBy流的结果应用操作

时间:2017-06-05 06:57:33

标签: lambda java-8 java-stream

我有一个水果列表,其中包含姓名和ID

List<Fruit> fruitList = Arrays.asList(new Fruit("apple", 1), new Fruit("orange", 2), new Fruit("orange", 3));

我想用name_Id重命名水果名称,如果存在重复的水果名称,就像我的列表橙色将重命名为orange_2和orange_3但苹果将保持苹果.. 如何在单流表达式中完成。

我想出的解决方案是

Map<String, List<Fruit>> fruitMap = fruitList.stream().collect(Collectors.groupingBy(Fruit::getName));

        Set<Entry<String, List<Fruit>>> entry = fruitMap.entrySet();

        for (Entry<String, List<Fruit>> en : entry) {
            List<Fruit> fruit = en.getValue();
            if (fruit.size() > 1) {
                fruit.stream().map(d -> {
                    d.setName(d.getName() + "_" + d.getId());
                    return d;
                }).collect(Collectors.toList());
            }
        }    
    }

但这不止一个流表达式。

3 个答案:

答案 0 :(得分:3)

这是一种(某种)单行:

fruitList.stream().collect(Collectors.groupingBy(Fruit::getName))
    .values().stream()
        .filter(list -> list.size() > 1)
        .forEach(list -> list.forEach(Fruit::renameWithId));

这假设您在Fruit中有以下方法:

public void renameWithId() {
    name = name + "_" + id;
}

如果您无法修改Fruit课程,则可以重新命名内联:

fruitList.stream().collect(Collectors.groupingBy(Fruit::getName))
    .values().stream()
        .filter(list -> list.size() > 1)
        .forEach(list -> list.forEach(fruit ->
            fruit.setName(fruit.getName() + "_" + fruit.getId())));

这些长单行很长,以至于它们不再是单行,尽管它们的名字......此外,代码最终难以读取并且难以维护和测试。因此,我建议您移动遍历地图的代码,并将水果重命名为新方法:

private void renameRepeatedFruits(Map<String, List<Fruit>> fruitMap) {
    fruitMap.values().stream()
        .filter(list -> list.size() > 1)
        .forEach(list -> list.forEach(Fruit::renameWithId));
}

这将允许您将代码的第一个版本大大简化为:

renameRepeatedFruits(
    fruitList.stream().collect(Collectors.groupingBy(Fruit::getName)));

答案 1 :(得分:2)

我不认为你可以在没有流媒体的情况下离开几次。这是一个更小的解决方案,我认为稍微更具可读性:

 Set<String> repeated = fruits.stream()
            .collect(Collectors.groupingBy(Fruit::getName, Collectors.counting()))
            .entrySet()
            .stream()
            .filter(e -> e.getValue() > 1)
            .map(Entry::getKey)
            .collect(Collectors.toSet());

    fruits.forEach(f -> {
        if (repeated.contains(f.getName())) {
            f.setName(f.getName() + "_" + f.getId());
        }
    });

    System.out.println(fruits); // [name = apple id = 1, name = orange_2 id = 2, name = orange_3 id = 3] 

答案 2 :(得分:0)

下面是我提出的代码,但它仍然是2表达式

Map<String, Long> fruitMap = fruitList.stream()
                .collect(Collectors.groupingBy(Fruit::getName, Collectors.counting()));

        fruitList.forEach(f -> {
            if (fruitMap.get(f.getName()) > 1) {
                f.setName(f.getName() + "_" + f.getId());
            }
        });