具有两个列表的Java8流
我有一个方法将2个列表作为参数,正如您在方法体中看到的那样,我想做一些过滤并将结果返回给调用方。我想用lambda表达式将这段代码转换成Java8流,但我想不出来。我最终为此创建了多个流,这超出了重构(IMHO)的目的。我想知道的是,我如何以一种简单的方式将其重构为一个流具有两个列表的Java8流,java,java-8,java-stream,Java,Java 8,Java Stream,我有一个方法将2个列表作为参数,正如您在方法体中看到的那样,我想做一些过滤并将结果返回给调用方。我想用lambda表达式将这段代码转换成Java8流,但我想不出来。我最终为此创建了多个流,这超出了重构(IMHO)的目的。我想知道的是,我如何以一种简单的方式将其重构为一个流 public Set<CustomerTrack> getCustomerTracks(List<CusomerTrack> tracks, List<Customer> customers
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;
}
公共设置getCustomerTracks(列出曲目,列出客户){
Set tracksToSave=new HashSet();
用于(客户:客户){
if(customer.getTrack()==null){
继续;
}
Long allowedTrackId=customer.getTrack().getId();
用于(CustomerTrack轨迹:轨迹){
if(Long.valueOf(track.getId()).equals(allowedTrackId)){
tracksToSave.add(曲目);
}
}
}
返回轨道保存;
}
看来这就是你想要的:
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
,您都在迭代整个曲目列表
;这具有O(n*m)
复杂性。这通常被认为是不好的,你可以改进它
为了使它更好,您应该首先从Customer
创建一个id的HashSet
;有了这个HashSet
你现在可以用你感兴趣的ID调用contains
,因为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()));
Set=customers.stream()
.filter(c->c.getTrack()!=null)
.map(c->c.getTrack().getId())
.collect(收集器.toSet());
设置tracksToSave=tracks.stream()
.filter(track->set.contains(track.getId())
.collect(Collectors.toSet());
您可以试试这样的方法
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());
这里的重要操作符是
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());
Set tracksToSave=customers.stream()
.map(客户::getTrack)
.filter(轨迹->轨迹!=null)
.flatMap(曲目->{
tracks.stream.filter(it->Long.valueOf(it.getId()).equals(track.getId()))
.collect(收集器.toSet());
首先,您可以创建一组允许的ID:
Set<Long> collect = customers.stream()
.filter(customer -> customer.getTrack() != null)
.map(customer -> customer.getTrack().getId())
.collect(Collectors.toSet());
Set collect=customers.stream()
.filter(客户->客户.getTrack()!=null)
.map(客户->客户.getTrack().getId())
.collect(收集器.toSet());
然后你可以填充你的曲目集
Set<CusomerTrack> tracksToSave = tracks.stream()
.filter(track -> collect.contains(Long.valueOf(track.getId())))
.collect(Collectors.toSet());
Set tracksToSave=tracks.stream()
.filter(track->collect.contains(Long.valueOf(track.getId()))
.collect(收集器.toSet());
试试这个
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);
});
有利于方法引用使用的另一种方式:
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());
设置轨迹=
customers.stream()
.map(Customer::getTrack)//要跟踪的客户
.filter(Objects::nonNull)//保持非null跟踪
.map(Track::getId)//Track-to-trackId
.flatMap(trackId->tracks.stream()//收集与trackId匹配的轨迹
.filter(t->Long.valueOf(t.getId()).equals(trackId))
)
.收集(toSet());
您需要先过滤空值,然后使用customerTrack列表对其进行过滤
希望这个答案对你有帮助
return customers.stream().map(cust-> cust.track).filter(track -> track != null).
collect(Collectors.toList())
.stream().filter(track-> customerTracks.stream()
.anyMatch(ele -> ele.getId() ==
track.getId())).collect(Collectors.toSet());
我真的建议您将轨迹放入id-->对象的hashmap中,现在您得到了O(n2)复杂度,这根本不是efificient@maslan关于你提到的问题,你有什么消息来源我可以读到吗?我想很好地理解:)(我想我现在理解这个问题了)。感谢您指出。问题很简单,如果
客户
中有ID,您就有一个列表
;对于每个ID,您都要遍历跟踪
列表以找到您需要的内容。遍历列表具有O(n)
复杂性,因为您对每个元素都这样做,所以您的总体复杂性是O(n*m)
。如果您首先从客户
创建一个ID集
,您将提高效率,因为在集中包含
,其复杂性为O(1)
@Eugene(集
哈希集
,不同于例如树集
和O(log n))-我说的对吗?所以你仍然需要遍历一个集合(它是O(n)
),但是现在在另一个集合中搜索是O(1)
;从而使总时间为O(n)+O(1)
,因为O(1)
是常量,它可以被删除,从而使你的总解O(n)
-比以前好多了。那不会编译,flatMap
需要返回一个流
,你返回一个集
,dehasi的答案可能更好。我被Lambda语法弄糊涂了-谢谢Eugene:DHi Eugene,你能告诉我最有效的方法吗?@Yonetmen刚刚做了。。。(我没有编译这段代码,我真诚地希望我没有遗漏任何东西,比如逗号或括号)谢谢你的回答,但是collect.contains(track.getId())
应该替换为collect.contains(Long.valueOf(track.getId())
@Yonetmen为什么简单明了的collect.contains(track.getId())
替换为collect.contains(Long.valueOf(track.getId())
?@Holger在我的例子中CustomerTrack
Id字段是字符串的一种类型。@Yonetmen这对于这个问题来说是一个有价值的信息。任何回答者都应该如何知道这个要求?为什么第一个customer.getTrack().getId()
返回一个Long
然后呢?@Holger好吧,这是我的错!我不应该指出它,因为它无关紧要。但既然你问了,我可以解释它。g