Java 8中是否有可能合并两个流?

3

我想知道能否在一次遍历中将两个预排序的流合并起来。例如,如果我有以下Java类:

public class Person { // constructor & getters ommitted
  private String name;
  private int salary;
  private List<Car> cars;
  public void addCar(Car c) { cars.add(c); }
}

public class Car { // constructor & getters ommitted
  private String owner;
  private String brand;
}

我有预先排序的流,例如:

Stream<Person> clients = Arrays.asList(
  new Person("Anne", 500), 
  new Person("Johnny", 340)
  ).stream();

Stream<Car> cars = Arrays.asList(
  new Car("Johnny", "Mazda"), 
  new Car("Johnny", "Fiat"), 
  new Car("Mary", "Volvo")
  ).stream();

我想使用 "Mazda" 和 "Fiat" 向 Johnny 应用 addCar()。Anne 没有汽车,Mary 不是客户。

能否在单个流上进行一次操作来合并两个流?

我看过一些解决方案,在其中一个流上多次遍历,但由于它们是预排序的,我想可能有机会一次性完成。

编辑: 操作的预期结果是两次为 "Johnny" 调用 addCar():一次是用 "Mazda",另一次是用 "Fiat"。


1
@Eugene,这不是被问到的内容。 - Konrad Rudolph
你加入操作的结果会是什么? - Naman
1
@KonradRudolph 我只看了标题,我承认。 - Eugene
1
相关链接:https://dev59.com/VGMm5IYBdhLWcg3wZ-XQ - Kayaman
1
流不是这个任务的适当数据结构。请将客户端排列为HashMap。 - Alexei Kaigorodov
显示剩余3条评论
2个回答

3

很遗憾,使用Stream API无法高效地解决这个任务。但是您仍然可以使用迭代器来完成它。

public static void addCars(Stream<Person> clients, Stream<Car> cars) {
    Iterator<Person> clientsIt = clients.iterator();
    Iterator<Car> carsIt = cars.iterator();
    Person client = null;
    while (carsIt.hasNext()) {
        Car car = carsIt.next();
        while (client == null || !client.getName().equals(car.getOwner())) {
            if(!clientsIt.hasNext()) return;
            client = clientsIt.next();
        }
        client.addCar(car);
    }
}

我曾经担心这是不可能的。谢谢。+1 - Joe DiNottra
@Naman 复杂度为 O(cars + clients)。外部循环最多执行 cars.size() 次,因为每次迭代都会调用 carsIt.next()。内部循环总共最多执行 clients.size() 次,因为每次迭代都会调用 clientsIt.next(),而且每次都使用相同的 clientsIt。这是最快的解决方案,因为它只在 carsclients 上迭代一次,不会因使用像 HashMap 这样的容器而产生额外开销。 - IlyaMuravjov

1
一个预计算可以有所帮助。类似于:
Map<String, List<Car>> cars = Stream.of(
        new Car("Johnny", "Mazda"),
        new Car("Johnny", "Fiat"),
        new Car("Mary", "Volvo"))
        .collect(Collectors.groupingBy(Car::getOwner));

Stream.of(new Person("Anne", 500),
        new Person("Johnny", 340))
        .forEachOrdered(p -> cars.getOrDefault(p.getName(), 
                Collections.emptyList()).forEach(p::addCar));

2
你的解决方案的复杂度是多少?是O(n^2)吗? - Alexei Kaigorodov
这个解决方案忽略了两个流已经被排序的事实。不过它确实可以工作。 - Joe DiNottra
1
@AlexeiKaigorodov 复杂度为 _O(cars + clients)_,因为 HashMap 在常数时间内执行操作。 - IlyaMuravjov
@JoeDiNottra 如果需要,您可以特别标记要按顺序处理的Stream。在现有代码中将forEach更改为forEachOrdered。已更新答案。 - Naman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接