具有两个列表的Java 8流

时间:2018-09-24 11:05:22

标签: java java-8 java-stream

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

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;
}

7 个答案:

答案 0 :(得分:5)

似乎这就是您所追求的:

 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)的复杂性。通常认为这很糟糕,您可以改善它。

要使其变得更好,您首先要从HashSet创建一个Customer个ID;有了HashSet之后,您现在就可以使用您感兴趣的ID调用contains,因为contains的时间复杂度为O(1)(实际上称为 amortized 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()));

答案 1 :(得分:1)

首先,您可以创建一组允许的ID:

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

然后您可以填充曲目收藏

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

答案 2 :(得分:1)

支持方法引用用法的另一种方式:

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

答案 3 :(得分:0)

您可以尝试这样的事情

customers
    .stream()
    .map(Customer::getTrack)
    .filter(Objects::nonNull)
    .map(CustomerTrack::getId)
    .flatMap(trackId -> tracks
                        .stream()
                        .filter(track -> Long.valueOf(track.getId()).equals(trackId)))
    .collect(Collectors.toSet());

答案 4 :(得分:0)

这里的重要运算符是flatMap

Set<CustomerTrack> tracksToSave = customers.stream()
   .map(Customer::getTrack)
   .filter(track -> track != null)
   .flatMap(track -> {
      tracks.stream.filter(it -> Long.valueOf(it.getId()).equals(track.getId())))
   .collect(Collectors.toSet());

答案 5 :(得分:0)

尝试这个

customers.stream()
          .filter(customer -> customer.getTrack() != null)
          .map(c -> c.getTrack().getId())
          .forEach(allowedTrackId -> { 
           tracks.stream()
          .filter(track -> Long.valueOf(track.getId()).equals(allowedTrackId))
          .forEach(tracksToSave::add);
});

答案 6 :(得分:0)

您需要先过滤null值,然后再使用customerTrack列表对其进行过滤。

希望这个答案对您有帮助。

'exclude'