【问题标题】:Java 8 Streams filtering out empty String[] from List<String[]>?Java 8 Streams 从 List<String[]> 中过滤出空 String[]?
【发布时间】:2021-06-07 16:01:54
【问题描述】:

假设我们有 2 个测试 String[],类似于:

String[] test = {"","","","",""};
String[] test2 = {"Test","Name", "5.00", "NY", "Single"};

然后我们将它们附加到这样的列表中:

List<String[]> testList = new ArrayList<>();
testList.add(test);
testList.add(test2);

我试图做的目标是使用 Java 8 流在每个 String[] 的索引 2 中找到支付的美元总和。但我似乎无法过滤掉每个索引中包含空值的 String[]。这是我的尝试:

public static void main(String[] args) {
        String[] test = {"","","","",""};
        String[] test2 = {"Test","Name", "5.00", "NY", "Single"};
        List<String[]> testList = new ArrayList<>();
        testList.add(test);
        testList.add(test2);
        System.out.println(testList);
        testList.stream().map(Arrays::asList).filter(i -> !i.isEmpty())
                                             .mapToDouble(columnsPerRow -> 
                                                Double.parseDouble(columnsPerRow.get(2)))
                                             .sum();
        System.out.println(testList);
    }

我尝试过滤它是使用 filter(i -> !i.isEmpty())

它抛出的错误仍然是:

Exception in thread "main" java.lang.NumberFormatException: empty String
    at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842)
    at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
    at java.lang.Double.parseDouble(Double.java:538)
    at Main.lambda$main$0(Main.java:23)
    at java.util.stream.ReferencePipeline$6$1.accept(ReferencePipeline.java:244)
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
    at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.DoublePipeline.collect(DoublePipeline.java:500)
    at java.util.stream.DoublePipeline.sum(DoublePipeline.java:411)
    at Main.main(Main.java:23)

【问题讨论】:

    标签: java java-8 stream java-stream


    【解决方案1】:

    i -&gt; !i.isEmpty()中,iArrayList,它包含("","","","",""),它不为空,你可以检查索引2处的值,你可以这样做

    double r = testList.stream().map(Arrays::asList)
                       .filter(i -> !i.isEmpty())              // ensure list not empty
                       .map(i -> i.get(2))                     // keep only 3rd element
                       .filter(i -> !i.isEmpty())              // ensure string isn't empty
                       .mapToDouble(Double::parseDouble)       // map to double
                       .sum();
    

    第一个.filter(i -&gt; !i.isEmpty())可以替换为.filter(i -&gt; i.size() &gt;= 3)

    【讨论】:

      【解决方案2】:

      您过滤了错误的实体:

      public static void main(String[] args)
      {
          String[] test = {"","","","",""};
          String[] test2 = {"Test","Name", "5.00", "NY", "Single"};
          String[] test3 = {"Test","Name", "13.00", "NY", "Single"};
          List<String[]> testList = new ArrayList<>();
          testList.add(test);
          testList.add(test2);
          testList.add(test3);
          double sum = testList.stream()
                          .map(Arrays::asList)
                          .filter(i -> i.size() > 2 && !i.get(2).isEmpty())
                          .mapToDouble(columnsPerRow -> Double.parseDouble(columnsPerRow.get(2)))
                          .sum();
          System.out.println(sum);
      }
      

      按预期生成18.0

      过滤阶段会移除少于 2 个元素或第 2 个元素为空的数组。

      【讨论】:

      • 请问.filter(i -> i.size() > 1) 部分是做什么的?
      • 防止您在输入数组的元素少于 2 个时尝试调用 get(2),这将引发 IndexOutOfBoundsException。如果您可以证明保证输入数组都具有超过 2 个元素,则可以省略它。
      • 我还有一个错字,我的意思是i.size() &gt; 2。固定。
      • 非常感谢,我之前实际上使用过 .filter(i -> !i.get().isEmpty)) ,但由于某种原因,我试图取出整个 String[]通过过滤掉其中的每一个指数而不是只过滤重要的指数,我感到羞耻哈哈谢谢你
      • @azro 确实如此,但即使是 map(Arrays::asList) 也完全没有必要。任务可以简单到testList.stream().map(a -&gt; a.length &gt; 2? a[2]: "") .filter(s -&gt; !s.isEmpty()) .mapToDouble(Double::parseDouble) .sum()
      【解决方案3】:

      相信你的话,过滤掉每个索引中包含空值的 String[]。

          String[] test = {"","","","",""};
          String[] test2 = {"Test","Name", "5.00", "NY", "Single"};
      
          double total = Stream.of(test, test2)
                  .filter(arr -> !Arrays.stream(arr).allMatch(String::isEmpty))
                  .mapToDouble(arr -> Double.parseDouble(arr[2]))
                  .sum();
          
          System.out.println(total);
      

      输出是:

      5.0

      我的代码只过滤出 all 值为空字符串的字符串数组。因此,如果美元值为 "" 并且数组包含其他非空字符串,它将出现异常。没有美元值的数组需要只保存空字符串,这就是您应该想要的。为了验证。您可能想要捕获NumerFormatException 并报告验证错误。或者在进行计算之前验证流。

      【讨论】:

      • 有了上面的答案,我不能在你的 .filter(arr -> !Arrays.stream(arr).allMatch(String::isEmpty)) 上加上这两种情况吗?
      • 我不确定你的意思是哪两个场景,或者通过结合两个答案你会赢得什么,但是是的,你当然可以做到。
      猜你喜欢
      • 2019-01-08
      • 2015-07-26
      • 2021-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-02
      • 1970-01-01
      • 2014-09-15
      相关资源
      最近更新 更多