首页 > 解决方案 > 带有两个列表的 Java 8 流

问题描述

我有一个方法需要 2 个列表作为参数,正如您在方法主体中看到的那样,我想做一些过滤并将结果返回给调用者。我想用 lambda 表达式将此代码转换为 Java 8 流,但我想不通。我最终为此创建了多个流,这超出了重构的目的(恕我直言)。我想知道的是,我如何以一种简单的方式将其重构为一个流?

public Set<CustomerTrack> getCustomerTracks(List<CusomerTrack> tracks, List<Customer> customers) {
    Set<CustomerTrack> tracksToSave = new HashSet<>();
    for (Customer customer : customers) {
        if (customer.getTrack() == null) {
            continue;
        }
        Long allowedTrackId = customer.getTrack().getId();
        for (CustomerTrack track : tracks) {
            if (Long.valueOf(track.getId()).equals(allowedTrackId)) {
                tracksToSave.add(track);
            }
        }
    }
    return tracksToSave;
}

标签: javajava-8java-stream

解决方案


似乎这就是你所追求的:

 customers.stream() 
          .filter(c -> c.getTrack() != null)
          .map(c -> c.getTrack().getId())
          .flatMap(id -> tracks.stream().filter(track -> Long.valueOf(track.getId()).equals(id)))
          .collect(Collectors.toSet());

请注意,对于每个id您都在迭代整个 ; 列表tracks。这很O(n*m)复杂。这通常被认为很糟糕,您可以改进它。

为了使它更好,您首先要从;创建一个HashSetid 。Customer有了它,HashSet您现在contains可以使用您感兴趣的 id 来调用它,因为contains它的时间复杂度为O(1)(它实际上被称为摊销复杂度O(1))。所以现在你的复杂性变成了O(n)+ O(1),但是因为O(1)它是一个常数,它真的O(n)- 比你以前的要好得多。在代码中:

Set<Long> set = customers.stream()
            .filter(c -> c.getTrack() != null)
            .map(c -> c.getTrack().getId())
            .collect(Collectors.toSet());

Set<CusomerTrack> tracksToSave = tracks.stream()
            .filter(track -> set.contains(track.getId())
            .collect(Collectors.toSet()));

推荐阅读