Lambda 对流的groupBy结果应用操作

Lambda 对流的groupBy结果应用操作,lambda,java-8,java-stream,Lambda,Java 8,Java Stream,我有一份水果清单,里面有名字和ID List<Fruit> fruitList = Arrays.asList(new Fruit("apple", 1), new Fruit("orange", 2), new Fruit("orange", 3)); List-fruitList=Arrays.asList(新水果(“苹果”,1),新水果(“橙色”,2),新水果(“橙色”,3)); 仅当存在重复的水果名称时,我想用名称\ Id重命名水果名称,如在我的列表中,orange将重命

我有一份水果清单,里面有名字和ID

List<Fruit> fruitList = Arrays.asList(new Fruit("apple", 1), new Fruit("orange", 2), new Fruit("orange", 3));
List-fruitList=Arrays.asList(新水果(“苹果”,1),新水果(“橙色”,2),新水果(“橙色”,3));
仅当存在重复的水果名称时,我想用名称\ Id重命名水果名称,如在我的列表中,orange将重命名为orange\ 2和orange\ 3,但苹果将保持为apple。。 如何在单流表达式中执行此操作

我想出的解决办法是

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());
            }
        }    
    }
Map-fruitMap=fruitList.stream().collect(Collectors.groupingBy(Fruit::getName));
Set entry=fruitMap.entrySet();
对于(条目en:Entry){
List fruit=en.getValue();
如果(水果大小()>1){
fruit.stream()映射(d->{
d、 setName(d.getName()+“”+d.getId());
返回d;
}).collect(Collectors.toList());
}
}    
}

但这不仅仅是一种流表达式。

我认为你不需要流几次就可以逃脱。以下是一个较小的解决方案,我认为它更具可读性:

 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] 
Set repeated=fruits.stream()
.collect(Collectors.groupingBy(Fruit::getName,Collectors.counting())
.entrySet()
.stream()
.filter(e->e.getValue()>1)
.map(条目::getKey)
.collect(收集器.toSet());
水果。forEach(f->{
if(重复.contains(f.getName())){
f、 setName(f.getName()+“”+f.getId());
}
});
System.out.println(水果);//[name=apple id=1,name=orange\u 2 id=2,name=orange\u 3 id=3]

下面是我提出的代码,但它仍然在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());
            }
        });
Map-fruitMap=fruitList.stream()
.collect(Collectors.groupingBy(Fruit::getName,Collectors.counting());
结果列表。forEach(f->{
if(fruitMap.get(f.getName())>1){
f、 setName(f.getName()+“”+f.getId());
}
});
这里有一个(某种)单行线:

fruitList.stream().collect(Collectors.groupingBy(Fruit::getName))
    .values().stream()
        .filter(list -> list.size() > 1)
        .forEach(list -> list.forEach(Fruit::renameWithId));
这假设您在
中有以下方法:

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));
}

谢谢,但这仍然是在2个表达式中,这不是我正在寻找的…但将第二个操作链接到第一个操作时,它将更加简洁,而不是使用收集器<代码>fruitList.stream().collect(收集器.groupingBy(Fruit::getName)).values().stream().filter(list->list.size()>1.forEach(list->list.forEach(Fruit::renameWithId))
renameRepeatedFruits(
    fruitList.stream().collect(Collectors.groupingBy(Fruit::getName)));