英文:
Combining two streams into one
问题
考虑以下代码:
// ...
String currentName = ...
String newName = ...; // 可能与currentName相同。
// 在这种情况下,不应抛出异常
AnimalEntity animal = animalKeeper.getAnimals()
.stream()
.filter(a -> a.getName().equals(currentName))
.findFirst()
.orElseThrow(() -> new NoResourceException("找不到该名称的动物"));
if (animalKeeper.getAnimals()
.stream()
.filter(a -> !a.getName().equals(currentName))
.anyMatch(a -> a.getName().equals(newName))) {
throw new BadRequestException("您已经拥有该名称的动物");
}
// ...
代码可以正常工作,但我不满意需要对流进行两次迭代。
我是否可以以某种方式一次性地实现相同的结果?
英文:
Consider the following code:
// ...
String currentName = ...
String newName = ...; // possibly same as currentName.
// in such a case, no exception should be thrown
AnimalEntity animal = animalKeeper.getAnimals()
.stream()
.filter(a -> a.getName().equals(currentName))
.findFirst()
.orElseThrow(() -> new NoResourceException("No animal with that name"));
if (animalKeeper.getAnimals()
.stream()
.filter(a -> !a.getName().equals(currentName))
.anyMatch(a -> a.getName().equals(newName))) {
throw new BadRequestException("You already have animal with that name");
}
// ...
The code works fine, but I am not happy that I needed to iterate twice over the streams.
Can I somehow achieve the same result in one-go?
答案1
得分: 1
以下是翻译好的部分:
代码可以简化为:
- 一个无操作检查(新名称等于旧名称)
- 所有动物都不包含这个新名称
- 你可以通过旧名称找到动物
所以:
if (!newName.equals(oldName)) {
if (animalKeeper.getAnimals().stream()
.anyMatch(a -> a.getName().equals(newName))) {
throw new BadRequestException("您已经有了这个名称的动物");
}
Animal animal = animalKeeper.getAnimals().stream()
.filter(a -> a.getName().equals(oldName))
.findAny()
.orElseThrow(() -> new NoResourceException("没有这个名称的动物"));
animal.rename("Koniara");
}
一个关键的改进是能够通过名称查找动物。
if (!newName.equals(oldName)) {
if (animalKeeper.mapByName.containsKey(newName)) {
throw new BadRequestException("您已经有了这个名称的动物");
}
Animal animal = animalKeeper.mapByName.get(oldName);
if (animal == null) {
throw new NoResourceException("没有这个名称的动物");
}
animal.rename("Koniara"); // 移除+放入
}
HashMap 可以使这个过程更快。
你可以在一个流中最多收集两只动物,具有旧名称或新名称。但这不会改变时间复杂度:N 步骤,带有一个分支。而且只有在收集的结果大小为2时才能停止循环。这肯定不会更好看。两个单独的查询可能更快。
英文:
The code condenses to:
- a no-op check (new name being old name)
- that all animals do not contain this new name
- that you can find the animal by its old name
So:
if (!newName.equals(oldName)) {
if (animalKeeper.getAnimals().stream()
.anyMatch(a -> a.getName().equals(newName))) {
throw new BadRequestException("You already have animal with that name");
}
Animal animal = animalKeeper.getAnimals().stream()
.filter(a -> a.getName().equals(oldName))
.findAny()
.orElseThrow(throw new NoResourceException("No animal with that name"));
animal.rename("Koniara");
}
A crucial improvement would be be able to find animals by name.
if (!newName.equals(oldName)) {
if (animalKeeper.mapByName.containsKey(newName)) {
throw new BadRequestException("You already have animal with that name");
}
Animal animal = animalKeeper.mapByName.get(oldName);
if (animal == null) {
throw new NoResourceException("No animal with that name"));
}
animal.rename("Koniara"); // remove+put
}
A HashMap would make that fast.
You could in one stream collect at most 2 animals, with old or new name. But it does not change anything in time complexity: N steps with one branching. Also you can only stop looping when the collected result size is 2. That certainly does not look better. 2 Separate queries can be faster.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论