Skip to content

Instantly share code, notes, and snippets.

@timyates
Last active May 30, 2016 08:32
Show Gist options
  • Save timyates/8686020 to your computer and use it in GitHub Desktop.
Save timyates/8686020 to your computer and use it in GitHub Desktop.
Implementing Groovy's collate method in Java 8 Streams
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/* Efficiency must be questioned
*
* Also, no error checking, so could go infinite if called with dodgy params
*
* (left as an exercise for the reader) ;-)
*/
public class Collate {
public <T> List<List<T>> collate( List<T> list, int size, int step ) {
return Stream.iterate( 0, i -> i + step )
.limit( ( list.size() / step ) + 1 )
.map( i -> list.stream()
.skip( i )
.limit( size )
.collect( Collectors.toList() ) )
.filter( i -> !i.isEmpty() )
.collect( Collectors.toList() ) ;
}
public static void main( String[] args ) {
Collate c = new Collate() ;
List<Integer> test = Arrays.asList( 1, 2, 3, 4, 5, 6, 7, 8, 9 ) ;
// Prints [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9], [9]]
System.out.println( c.collate( test, 3, 1 ) ) ;
// Prints [[1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9], [9]]
System.out.println( c.collate( test, 3, 2 ) ) ;
// Prints [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
System.out.println( c.collate( test, 3, 3 ) ) ;
}
}
@mperry
Copy link

mperry commented Jan 30, 2014

@timyates

You might like to write unfold for Streams in Java 8 using "of" and "concat". Implementing collate using unfold is easier and far more concise, as you saw in my implementation.

You should be able to use Stream.iterate instead of generate to simplify things, something like:
iterate(step, i-> i + step)

@timyates
Copy link
Author

@mperry I wish gists emailled me when a comment was added ;-)

Cool! Added the Stream.iterate (I'd not seen that before, very nice), and I'll look onto unfold now :-D

@timyates
Copy link
Author

@mperry Does this look right for the unfold method?

    class Pair<T,U> {
        private final T left ;
        private final U right ;

        public Pair( T left, U right ) {
            this.left = left ;
            this.right = right ;
        }

        public T getLeft()  { return left; }
        public U getRight() { return right; }
    }

    private <T,U> List<T> unfold( U val, Function<U,Optional<Pair<T,U>>> f ) {
        List<T> ret = new ArrayList<>() ;
        while( true ) {
            Optional<Pair<T,U>> r = f.apply( val ) ;
            if( !r.isPresent() ) {
                break ;
            }
            Pair<T,U> o = r.get() ;
            ret.add( o.getLeft() ) ;
            val = o.getRight() ;
        }
        return ret ;
    }

    public <T> List<List<T>> collate2( List<T> list, int size, int step ) {
        return unfold( list, i -> 
                i.isEmpty() ? 
                    Optional.empty() : 
                    Optional.of( new Pair<>( i.subList( 0, Math.min( size, i.size() ) ),
                                             i.subList( Math.min( step, i.size() ), i.size() ) ) ) ) ;
    }

@mperry
Copy link

mperry commented Jan 30, 2014

Looks about right. Is this exactly the same implementation as above, in particular the need for Math.min? I could probably figure it out myself, but don't have the time at the moment to. Pair implementation looks ok, unfortunately Java does not support any tuple type. As an aside, I got FunctionalJava working with Java 8, I will have to get this organised soon - best to use FJ's P (product type) to produce a P2 for the pair. On this point, I would add a static method to produce the pair, to get rid of the ugly instantiation.

@timyates
Copy link
Author

Without Math.min, sublist walks off the end of the list when you get near the end :-(

Yeah, I think people have been asking for java.util.Pair for a long time

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment