【问题标题】:java stream list of filtersjava流过滤器列表
【发布时间】:2019-02-19 13:10:01
【问题描述】:

假设我有一个字符串列表,我想通过过滤字符串列表过滤它们。 对于包含以下内容的列表: “abcd”、“xcfg”、“dfbf”

我会精确列出过滤字符串: “a”,“b”,在类似 filter(i->i.contains(filterStrings) 之后,我想收到“abcd”,“dfbf”的列表, 对于过滤字符串列表: "c", "f" 我想获取 "xcfg" 和 "dfbf" 的列表。

List<String> filteredStrings = filteredStrings.stream()
            .filter(i -> i.contains("c") || i.contains("f")) //i want to pass a list of filters here
            .collect(Collectors.toList());

除了扩展 lambda 表达式的主体并编写一个带有标志的函数来检查每个过滤器之外,还有其他方法吗?

【问题讨论】:

  • 顺便说一下,如果我错了,请纠正我,我假设第二个输出还应该包括abcd,因为c的存在?
  • @nullpointer 是的,你是对的

标签: java filter java-stream


【解决方案1】:

您应该改为在列表上执行anyMatch 以匹配来自:

List<String> input = Arrays.asList("abcd", "xcfg", "dfbf"); // your input list
Set<String> match = new HashSet<>(Arrays.asList("c", "f")); // to match from
List<String> filteredStrings = input.stream()
        .filter(o -> match.stream().anyMatch(o::contains))
        .collect(Collectors.toList());

【讨论】:

    【解决方案2】:

    您可以使用简单的正则表达式更改您的contains

    .filter(i -> i.matches(".*[cf].*")) // to check just one character
    

    或:

    .filter(i -> i.matches(".*(c|f).*")) // or if you have a words
    

    【讨论】:

      【解决方案3】:

      过滤器可以表示为Predicate。在您的情况下为Predicate&lt;String&gt;。因此,过滤器列表可以存储在List&lt;Predicate&lt;String&gt;&gt;中。

      现在,如果您想在 Stream 的每个元素上应用这样的列表:

      List<String> filteredStrings = input.stream()
                                          .filter(i -> filterList.stream().anyMatch(f -> f.test(i))) 
                                          .collect(Collectors.toList());
      

      完成示例:

      List<String> input = new ArrayList<>(Arrays.asList ("abcd", "xcfg", "dfbf","erk"));
      List<Predicate<String>> filterList = new ArrayList<>();
      filterList.add (i -> i.contains("c"));
      filterList.add (i -> i.contains("f"));
      List<String> filteredStrings = input.stream()
                                          .filter(i -> filterList.stream().anyMatch(f -> f.test(i))) 
                                          .collect(Collectors.toList());
      System.out.println (filteredStrings);
      

      输出:

      [abcd, xcfg, dfbf]
      

      【讨论】:

      • 这需要创建一个List&lt;Predicate&gt;,每个Predicate 检查一个过滤器元素。 @nullpointer 的答案是可取的。
      【解决方案4】:

      您可以创建一个List,它具有任意数量的过滤器

      List<Predicate<String>> filterList = new ArrayList<>();
      Predicate<String> containsCPredicate = s -> s.contains("c");
      filterList.add(containsCPredicate);
      filterList.add(s -> s.contains("f"));
      ...
      

      然后您可以reduce 将这些过滤器列表合二为一,将它们组合起来:

      filterList.stream().reduce(i -> true, Predicate::and)
      

      在您的流管道上应用它们时,例如

      List<String> filteredStrings = strings.stream()
              .filter(filterList.stream().reduce(i -> true, Predicate::and))
              .collect(Collectors.toList());
      

      初始i -&gt; truePredicate是身份,reduce操作需要作为第一个参数。

      【讨论】:

        【解决方案5】:

        您可以使用Pattern

        static final Pattern pattern = Pattern.compile("c|f");
        

        然后检查字符串是否与所述模式匹配。

        List<String> strings = filteredStrings.stream()
            .filter(s -> pattern.matcher(s).find())
            .collect(Collectors.toList());
        

        pattern 当然可以通过给定的输入来计算:

        public static Pattern compute(String... words) {
            StringBuilder pattern = new StringBuilder();
            for(int i = words.length - 1; i >= 0; i++) {
               pattern.append(words[i]);
               if(i != 0) {
                   pattern.append('|');
               }
            }
            return Pattern.compile(pattern);
        }
        

        然后可以这样调用:

        Pattern patten = compute("some", "words", "hello", "world");
        

        这将导致一个正则表达式:

        some|words|hello|world
        

        【讨论】:

        • 您应该记住,对于未知输入,您不能排除单词包含对正则表达式引擎具有特殊含义的字符。另一方面,您可以使用像Arrays.stream(words) .map(Pattern::quote) .collect(Collectors.joining("|")) 这样简单的Stream API 来构造正则表达式,就像this answer 一样。如果您确定单词不包含特殊字符,则可以使用更简单的String.join("|", words)。无需处理应用程序代码中的StringBuilder...
        • ...而不是.filter(s -&gt; pattern.matcher(s).find()),您可以简单地使用.filter(pattern.asPredicate())
        猜你喜欢
        • 2021-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-26
        • 2020-02-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多