将两个流合并为一个流

huangapple go评论75阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2020年10月27日 00:02:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/64540744.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定