【问题标题】:How to remove elements from a list with lambda based on another list如何使用基于另一个列表的 lambda 从列表中删除元素
【发布时间】:2015-09-01 15:20:26
【问题描述】:

我有文件路径列表:.

List<Path> filePaths; //e.g. [src\test\resources\file\15\54\54_exampleFile.pdf]

上面的54指的是文件ID

然后我获得StringSet Id,我的应用程序可以按如下方式处理:

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

我如何使用 Java 8 lambdas 将 filter 中的所有元素排除在 filePaths 中,这些元素不包含 acceptedIds 集合 Set 中包含的任何可接受的 Id。

换句话说,我只想在filePaths 中保留ID 位于acceptedIds 中的路径。例如,54 不在上面的列表中,因此被删除。

filePaths.stream().filter(...).collect(Collectors.toList());

【问题讨论】:

  • 我们可以依赖以 ID 命名的直接父目录吗?
  • filePaths.removeIf(p -> !acceptedIds.contains(p.getPath())

标签: java lambda java-8 java-stream


【解决方案1】:

最有效的方法是从路径中提取ID,然后尝试在Set中找到它,使每个过滤器在恒定时间内执行,即O(1)给出一个整体O(n),其中n是路径数:

filePaths.stream()
  .filter(p -> acceptedIds.contains(p.getParent().getFileName().toString()))
  .collect(Collectors.toList());

如果执行反向方法,在路径中搜索每个acceptedIds(如其他答案),每个过滤器都是O(m*k),其中macceptedIdsk 的数量是平均路径长度,给出一个整体O(n * m * k),即使是中等大小的集合,它的性能也会很差。

【讨论】:

  • 提取时我应该如何trim() 空格的 id ?
  • 空白在哪里?在路径中,例如"src\test\resources\file\15\54 \54_exampleFile.pdf"(目录名称为"54 " - 带有空格),或者存储在acceptedIds中的值中?
  • 为提高效率,应将 Set 中的值修剪一次(最好在 connection.getAcceptedIDs() 内),但要在您的方法中进行,acceptedIds = acceptedIds.stream().map(String::trim).collect(Collectors.toSet());
  • connection.getAcceptedIDs() 是我的连接模型的吸气剂。那么我应该从那个方法返回return acceptedIds.stream().map(String::trim).collect(Collectors.toSet()); 是你的意思吗?我更愿意按照你在 getter 中所说的进行修剪
  • @user2781389 很简单 - 只需在拆分期间修剪它们! &lt;constructor-arg value="#{'${file.specifiedIds}'.trim().split(' *, *')}" :)
【解决方案2】:

你可以写:

filePaths.stream()
         .filter(p -> acceptedIds.stream().anyMatch(id -> p.toString().contains(id)))
         .collect(toList());

这会过滤每个路径,以使acceptedIds 中的至少一个包含在路径的字符串表示中。您可能希望在此处实现比 contains 更好的东西,具体取决于您的用例(例如匹配文件名的开头)。

anyMatch 是一种确定至少一个元素是否与给定谓词匹配的操作。

请注意,此答案并未对过滤掉元素的路径做出任何假设。如果您可以放心地说,在每个路径中,父目录都以 id 命名,那么出于性能原因,您绝对应该使用@Bohemian 答案。

【讨论】:

  • p.toString().contains(id) 暗示 "54".contains("4")"543".contains("4") 我怀疑这是否符合 OP 的意图。
  • @Holger 我同意,这就是为什么我说他可能想要实现更好的东西(比如匹配文件名的开头)。
【解决方案3】:

像这样:

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

【讨论】:

    【解决方案4】:

    如果您的文件名结构不变,我会先使用正则表达式来提取数字,然后检查它是否在所需的 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"));
    })
    ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-11-13
      • 2014-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-20
      相关资源
      最近更新 更多