How to generate all k-sublists of a list in Java?

Viewed 1935

Let's consider:List <String> ints = Arrays.asList("1","2","3","4","5","6") and let k=2.

We would like to return following list List<String> : ["12", "23", "34", "45", "56"]

What about elegant solutions? Is it possible to do it with streams ?

Of course it can be solved in many ways, the simplest is iterating over whole list with nested list 1...k.

Any ideas?

2 Answers

With Streams:

        final List<String> ints = Arrays.asList("1", "2", "3", "4", "5", "6");
        final int k = 2;
        final List<String> result = IntStream.iterate(0, i -> i + 1).limit(ints.size() - k + 1)
                .mapToObj(i -> ints.subList(i, i + k).stream().reduce("", (a, b) -> a + b + ""))
                .collect(Collectors.toList());

        System.out.println(result);3

With a for loop:

    List<String> result = new LinkedList<>();
    for(int i = 0 ; i < ints.size() - k + 1; i++) {
        StringBuilder sb = new StringBuilder();
        for(int j = 0; j < k; j++) {
            sb.append(ints.get(i+j));
        }
        result.add(sb.toString());
    }

    System.out.println(result);

Now decide yourself ;-)

If you can live with a Collection<String> instead of a List<String> in your result, then you could use Java 9's Collectors.flatMapping:

Collection<String> result = IntStream.range(0, ints.size() - k)
    .boxed()
    .collect(Collectors.groupingBy(i -> i, 
        Collectors.flatMapping(i -> ints.subList(i, i + k).stream(), 
            Collectors.joining())))
    .values();

Another way, similar to IEE1394's answer:

List<String> result = IntStream.range(0, ints.size() - k)
    .mapToObj(i -> String.join("", ints.subList(i, i + k)))
    .collect(Collectors.toList());
Related