3

I have a list of integers and I want to return sub lists of integers from this list using java 8 streams where my sub list contain all the positive integers from original list just before it encounters a negative integer

For ex. let's say my list have elements

[1 , 2 , 0 , -1 , 5 , 8 , 9 , -11 , 7 , 13 ]

then I should return sub lists containing

  [1 , 2 , 0 ] [ 5 , 8 , 9 ] [7 , 13]  

I tried following approach but it's not working, your direction & input is much appreciated.

package Java8;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

public class StreamsExamples {

    public static void main(String[] args) {
        ArrayList<Integer> arr = new ArrayList<Integer>();
        arr.add(1);
        arr.add(2);
        Integer[] al = new Integer[]{0,-1,5,8,9,-11,7,13};
        arr.addAll(Arrays.asList(al));
        arr.stream().collect(Collectors.groupingBy(Functionality::getPositiveList));
        // arr.stream().collect(Collectors.toList()).;
        //arr.stream().sorted().forEach(System.out::print);
    }


}

class Functionality{

    public List<List<Integer>> getPositiveList(List<Integer> list){
        List<List<Integer>> li = new ArrayList<List<Integer>>();
        List<Integer> a = new ArrayList<Integer>();
        for(int i=0;i<list.size();i++) {
            if(list.get(i)>=0) {
                a.add(list.get(i));
            }
            else if (list.get(i)<0) {
                li.add(a);
                a.clear();
            }
        }
        return li;

    }
}
Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
Sid
  • 205
  • 3
  • 8
  • 1
    using stream API in case of your problem isn't good. going with classic loop is more readable. `List temp = new ArrayList<>(); for (Integer integer : arr) { if (integer < 0) { result.add(temp); temp = new ArrayList<>(); } else temp.add(integer); } result.add(temp);` – Hadi J Jun 16 '19 at 07:08
  • 1
    For such problems, I would go with the classic `foreach` loop. Stream API is not a swiss army knife. – Govinda Sakhare Jun 16 '19 at 07:19

2 Answers2

5

This isn't so hard if you think a bit different here: find out the indexes where the negative value is and just do a subList between those... There are some quirks to do with IntStream.of(-1) (but I'll let you figure it out why it is like that: try to replace it with the more intuitive IntStream.of(0) and see what is going on). So having an input like:

ArrayList<Integer> arr = List.of(1, 2, 0, -1, 5, 8, 9, -11, 7, 13);

You first find out the indexes:

int[] indexes = IntStream.concat(
IntStream.of(-1),
IntStream.concat(
      IntStream.range(0, arr.size())
               .filter(x -> arr.get(x) < 0),
      IntStream.of(arr.size())))
         .toArray();

System.out.println(Arrays.toString(indexes));

This will give a result like: [-1, 3, 7, 10].

Thus just compute the subList between these:

IntStream.range(0, indexes.length - 1)
         .mapToObj(x -> arr.subList(indexes[x] + 1, indexes[x + 1]))
         .collect(Collectors.toList())
         .forEach(System.out::println);
Eugene
  • 117,005
  • 15
  • 201
  • 306
2

It's a bit ugly, but this works:

List<List<Integer>> lists = Arrays.stream(arr).boxed()
    .reduce(
        new ArrayList<>(),
        (l, i) -> {
            if (l.isEmpty() || i < 0) {
                l.add(new ArrayList<>());
            }
            if (i >= 0) {
                l.get(l.size() - 1).add(i);
            }
            return l;
        }, (a, b) -> {
            a.addAll(b);
            return a;
        });

Tested:

int [] arr = {1, 2, 0, -1, 5, 8, 9, -11, 7, 13};

List<List<Integer>> lists = Arrays.stream(arr).boxed().reduce(new ArrayList<>(),
        (l, i) -> {
            if (l.isEmpty() || i < 0) {
                l.add(new ArrayList<>());
            }
            if (i >= 0) {
                l.get(l.size() - 1).add(i);
            }
            return l;
        }, (a, b) -> {
            a.addAll(b);
            return a;
        });

System.out.println(lists);

Output:

[[1, 2, 0], [5, 8, 9], [7, 13]]
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • Do not use `Stream.reduce()` for this, because it's violating the contract of `reduce()`. See [Reduction](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#Reduction) and [Mutable Reduction](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#MutableReduction) or [Java 8 Streams - collect vs reduce](https://stackoverflow.com/q/22577197/9662601) for more information. Use `Stream.collect()` instead. – Samuel Philipp Jun 24 '19 at 21:20