具有两个列表的 Java 8 流

2022-09-04 21:52:15

我有一个方法将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;
}

答案 1

似乎这就是你所追求的:

 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());

请注意,对于每个您正在迭代的整个列表;这有复杂性。这通常被认为是不好的,你可以改进它。idtracksO(n*m)

为了使它更好,您首先从 中创建一个ids;有了它,你现在可以使用你感兴趣的id调用它,因为有一个时间复杂度(它实际上被称为摊销复杂度)。所以现在你的复杂性变成了+,但是由于是一个常数,它真的 - 比你以前拥有的要好得多。在代码中:HashSetCustomerHashSetcontainscontainsO(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()));

答案 2

另一种有利于方法参考用法的方法:

Set<Track> tracks = 
customers.stream()
         .map(Customer::getTrack) // customer to track
         .filter(Objects::nonNull) // keep non null track
         .map(Track::getId)      // track to trackId
         .flatMap(trackId -> tracks.stream() // collect tracks matching with trackId
                                   .filter(t-> Long.valueOf(t.getId()).equals(trackId))
         )
         .collect(toSet());

推荐