Lambda 对流的groupBy结果应用操作
我有一份水果清单,里面有名字和IDLambda 对流的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将重命
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)));