Java 如何使用基于另一个列表的 lambda 从列表中删除元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32335335/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to remove elements from a list with lambda based on another list
提问by M06H
I have List of file Paths: .
我有文件路径列表: .
List<Path> filePaths; //e.g. [src\test\resources\file_exampleFile.pdf]
54
above refers to file ID
54
以上是指文件ID
I then obtain a Set
of String
Ids which my application can handle as follows:
然后我获得了一个我的应用程序可以处理Set
的String
Id,如下所示:
Set<String> acceptedIds = connection.getAcceptedIDs(); //e.g. elements [64, 101, 33]
How can I use Java 8 lambdas to filter
out all elements in filePaths
that do not contain any of the acceptable Ids that are contained in acceptedIds
collection Set.
我如何使用 Java 8 lambda 来filter
删除filePaths
不包含acceptedIds
集合集中包含的任何可接受 Id 的所有元素。
In other words, I would like to retain in filePaths
only the paths that have ids which are in acceptedIds
set. For example, 54 is not in the above list so is removed.
换句话说,我只想保留filePaths
那些具有已acceptedIds
设置的id 的路径。例如,54 不在上面的列表中,因此被删除。
filePaths.stream().filter(...).collect(Collectors.toList());
采纳答案by Bohemian
The most efficient way is to extract the ID from the path, then attempt to find it in the Set, making each filter execute in constant time, ie O(1)
giving an overall O(n)
, where n
is the number of paths:
最有效的方法是从路径中提取ID,然后尝试在Set中找到它,使每个过滤器在恒定时间内执行,即O(1)
给出一个整体O(n)
,其中n
是路径数:
filePaths.stream()
.filter(p -> acceptedIds.contains(p.getParent().getFileName().toString()))
.collect(Collectors.toList());
If the reverse approach is done, where each acceptedIds
is searched for in the path (as in other answers), each filter is O(m*k)
, where m
is the number of acceptedIds
and k
is the average Path length, giving an overall O(n * m * k)
, which will perform very poorly for even moderate sizes of collections.
如果相反的方法完成,其中每个acceptedIds
被搜索的路径(在其他的答案),每一滤波O(m*k)
,这里m
是数量acceptedIds
和k
是平均路径长度,总给人一种O(n * m * k)
,它会执行得非常糟糕甚至适度集合的大小。
回答by Tunaki
You could write:
你可以写:
filePaths.stream()
.filter(p -> acceptedIds.stream().anyMatch(id -> p.toString().contains(id)))
.collect(toList());
This filters each path such that at least one of the acceptedIds
is contained in the string representation of the path. You might want to implement something better than contains
here, depending on your use-case (matching the beginning of the filename for example).
这将过滤每个路径,以便路径acceptedIds
的字符串表示中至少包含其中之一。contains
根据您的用例(例如匹配文件名的开头),您可能想要实现比这里更好的东西。
anyMatch
is an operation that determines if at least one element matches the given predicate.
anyMatch
是一种确定是否至少有一个元素与给定谓词匹配的操作。
Note that this answer does not make any assumption about the path to filter out elements. If you can safely say that in each path, the parent directory is named with the id, you should definitely go with @Bohemian answer, for performance reason.
请注意,此答案并未对过滤元素的路径做出任何假设。如果您可以放心地说,在每个路径中,父目录都以 id 命名,出于性能原因,您绝对应该使用 @Bohemian 答案。
回答by Xirema
Like so:
像这样:
List removeMissing(List l1, List l2) {
List ret = l1.stream()
.filter(o -> l2.contains(o)) //Keep if object o satisfies the condition "l2 contains a reference to this object"
.collect(Collectors.toList());
return ret;
}
回答by Danilo Pianini
If your file name structure is constant, I'd use a regex first to extract the number, and then will check if it is among the desired ids.
如果您的文件名结构是恒定的,我会首先使用正则表达式来提取数字,然后检查它是否在所需的 ID 中。
final Set<String> acceptedIds = ...
// Matches the number of the file, concluded with the underscore
final Pattern extractor = Pattern.compile("\.*(?<number>\d+)_")
filePaths.stream().filter( path -> {
final Matcher m = extractor
.matcher(path.getFileName().toString());
m.find();
return acceptedIds.contains(m.group("number"));
})
...