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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 12:21:45  来源:igfitidea点击:

How to remove elements from a list with lambda based on another list

javalambdajava-8java-stream

提问by M06H

I have List of file Paths: .

我有文件路径列表: .

List<Path> filePaths; //e.g. [src\test\resources\file_exampleFile.pdf]

54above refers to file ID

54以上是指文件ID

I then obtain a Setof StringIds which my application can handle as follows:

然后我获得了一个我的应用程序可以处理SetStringId,如下所示:

Set<String> acceptedIds = connection.getAcceptedIDs(); //e.g. elements [64, 101, 33]

How can I use Java 8 lambdas to filterout all elements in filePathsthat do not contain any of the acceptable Ids that are contained in acceptedIdscollection Set.

我如何使用 Java 8 lambda 来filter删除filePaths不包含acceptedIds集合集中包含的任何可接受 Id 的所有元素。

In other words, I would like to retain in filePathsonly the paths that have ids which are in acceptedIdsset. 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 nis 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 acceptedIdsis searched for in the path (as in other answers), each filter is O(m*k), where mis the number of acceptedIdsand kis 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是数量acceptedIdsk是平均路径长度,总给人一种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 acceptedIdsis contained in the string representation of the path. You might want to implement something better than containshere, depending on your use-case (matching the beginning of the filename for example).

这将过滤每个路径,以便路径acceptedIds的字符串表示中至少包含其中之一。contains根据您的用例(例如匹配文件名的开头),您可能想要实现比这里更好的东西。

anyMatchis 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"));
})
...