【问题标题】:How to return the entire list if filter is false如果过滤器为假,如何返回整个列表
【发布时间】:2019-06-24 13:43:36
【问题描述】:

我有这份清单

List<String> lstStr = new ArrayList<>();
lstStr.add("1");
lstStr.add("2");
lstStr.add("3");
lstStr.add("4");
lstStr.add("5");

当我搜索字符串 "1" 它应该返回一个 List&lt;String&gt; = ["1"] 并且如果搜索字符串不在列表中,例如 "0" 它应该返回整个List &lt;String&gt; =["1","2","3","4","5"]。这可以使用java流来实现吗?请举个例子。

我已经使用下面的代码进行了尝试,但是当我搜索 "0"

时,我可以获得整个列表
List<String> filteredLst = lstStr.stream()
                                  .filter(data-> "1".equalsIgnoreCase(data))
                                  .collect(Collectors.toList());

filteredLst.forEach(data2 -> System.out.println(data2));

提前致谢。

【问题讨论】:

    标签: java arraylist collections java-8 java-stream


    【解决方案1】:

    您可以对谓词进行分区并返回非空列表:

    Map<Boolean, List<String>> split = lstStr.stream()
            .collect(Collectors.partitioningBy("1"::equalsIgnoreCase));
    
    List<String> filteredLst = split.get(Boolean.TRUE).isEmpty() ? 
                            split.get(Boolean.FALSE) : //can also use lstStr instead
                            split.get(Boolean.TRUE);
    

    Collectors.partitioningBy("1"::equals) 将返回一个 2 条目映射,其中 true 将是满足您过滤器的条目的键,false 是其余条目的键。

    filteredLst 应该包含映射到 true 的值,如果它不为空,否则应该包含 false 的值(这肯定与他的原始列表相同)

    【讨论】:

    • 或者只是List&lt;String&gt; filteredLst = split.get(!split.get(true).isEmpty());
    【解决方案2】:

    如果您不需要处理重复项,则可以执行以下操作:

    static List<String> getOneOrAll(List<String> list, String element) {
        return list.stream()
                   .filter(element::equalsIgnoreCase)
                   .findFirst()
                   .map(Collections::singletonList)
                   .orElse(list);
    }
    
    ...
    List<String> result = getOneOrAll(lstStr, "1");
    

    否则你可以传入一个谓词并过滤重复项:

    static <T> List<T> getOneOrAll(List<T> list, Predicate<T> predicate) {
        List<T> filteredList = list.stream()
                                   .filter(predicate)
                                   .collect(toList());
        return filteredList.isEmpty() ? list : filteredList;
    }
    
    ...
    List<String> result = getOneOrAll(lstStr, "1"::equals);
    // or
    List<String> resultIgnoringCase = getOneOrAll(lstStr, "1"::equalsIgnoreCase);
    

    【讨论】:

    • 请记住,List.containsequalsIgnoreCase 的语义不同。
    • @Holger 是的,完全正确。这就是函数接受通用Predicate 的原因。有一天,OP 可能希望在不同的条件下重用相同的功能。
    • 您的第二个解决方案可以。您的第一个选择是通过list.contains 检查。
    • @Holger 这很有意义。更新了第一个解决方案。唯一需要注意的是 Arrays.asList(...) 返回一个不可变列表。
    • Arrays.asList 返回的列表不是不可变的。它仍然支持set 方法。它只是不支持调整大小,即 addremove 不起作用。但是由于没有关于可变性的规范,我会说不可变就可以了,特别是当结果可能是也可能不是原始列表时,这排除了基于预期可变性的合理应用程序逻辑。因此,您也可以使用.map(Collections::singletonList),它返回一个真正不可变(且更高效)的列表。
    【解决方案3】:

    一个可能的简单工具是使用contains

    List<String> findAndReturnValue(List<String> lstStr, String value) {
        return lstStr.contains(value) ? Arrays.asList(value) : lstStr;
    }
    

    对于列表中可能的重复项:

    List<String> findAndReturnValue(List<String> lstStr, String value) {
        return lstStr.contains(value) ?
                lstStr.stream()
                        .filter(a -> a.equalsIgnoreCase(value)) // condition as in question
                        .collect(Collectors.toList()) : lstStr;
    }
    

    为了降低元素出现在列表中的情况的复杂性,更简单的解决方案是收集到一个列表,然后检查大小:

    List<String> findAndReturn(List<String> lstStr, String value) {
        List<String> filteredLst = lstStr.stream()
                .filter(data -> data.equalsIgnoreCase(value))
                .collect(Collectors.toList());
        return filteredLst.isEmpty() ? lstStr : filteredLst;
    }
    

    【讨论】:

    • 与其他答案一样,请记住 List.contains 与通过 equalsIgnoreCase 进行测试的语义不同。
    【解决方案4】:

    您可以为此目的使用自定义收集器。

    li.stream().filter(d->"0".equalsIgnoreCase(d)).collect(
                Collector.of(
                        ArrayList::new,
                        ArrayList::add,
                        (a, b) -> {
                            a.addAll(b);
                            return a;
                        },
                        a -> a.isEmpty() ? li : a
                )
        );
    

    寻找收集器文档:https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collector.html

    【讨论】:

      【解决方案5】:

      首先检查您的列表是否包含该值。 如果是,那么去过滤列表 否则只打印上一个列表

      if(!lstStr.contains("0")) {
              lstStr.forEach(data2 -> System.out.println(data2));
          }else {
          List<String> filteredLst = lstStr.stream()
                  .filter(data-> "1".equalsIgnoreCase(data))
                  .collect(Collectors.toList());
          filteredLst.forEach(data2 -> System.out.println(data2));
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-06-14
        • 2018-10-23
        • 2017-08-07
        • 2022-12-05
        • 1970-01-01
        • 1970-01-01
        • 2023-03-21
        相关资源
        最近更新 更多