stackerstack
stackerstack

Reputation: 265

Java 8 Streams filtering out empty String[] from List<String[]>?

Assuming we have 2 test String[], something like:

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

And then we append them to a list like this:

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

The goal of what I am trying to do is to find the sum of the dollars paid, in index 2 of each String[] using Java 8 streams. But I can't seem to filter out the String[] containing empty values in each indice. Here is my attempt:

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

My attempt to filter it was using filter(i -> !i.isEmpty())

The error it throws is still:

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)

Upvotes: 1

Views: 1521

Answers (3)

Anonymous
Anonymous

Reputation: 86252

Taking your word for it, filter out the String[] containing empty values in each indice.

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

Output is:

5.0

My code only filters out string arrays where all the values are empty strings. So it will break with an exception if the dollar value is "" and the array contains other non-empty strings. Which is what you should want of an array without dollar value is required to hold only empty strings. For the sake of validation. You will probably want to catch the NumerFormatException and report a validation error. Or maybe validate the stream before doing your computation.

Upvotes: 1

Jim Garrison
Jim Garrison

Reputation: 86774

You're filtering on the wrong entity:

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

Produces 18.0 as expected.

The filter stage removes arrays that are shorter than 2 elements or where the 2nd element is empty.

Upvotes: 1

azro
azro

Reputation: 54148

In i -> !i.isEmpty(), i is the ArrayList, and it contains ("","","","","") si it isn't empty, you may check for the value at index 2, you can do it that way

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();

The first .filter(i -> !i.isEmpty()) could be replaced by .filter(i -> i.size() >= 3)

Upvotes: 2

Related Questions