I'm trying to split a list into a list of list where each list has a maximum size of 4.
I would like to know how this is possible to do using lambdas.
Currently the way I'm doing it is as follow:
List<List<Object>> listOfList = new ArrayList<>();
final int MAX_ROW_LENGTH = 4;
int startIndex =0;
while(startIndex <= listToSplit.size() )
{
int endIndex = ( ( startIndex+MAX_ROW_LENGTH ) < listToSplit.size() ) ? startIndex+MAX_ROW_LENGTH : listToSplit.size();
listOfList.add(new ArrayList<>(listToSplit.subList(startIndex, endIndex)));
startIndex = startIndex+MAX_ROW_LENGTH;
}
UPDATE
It seems that there isn't a simple way to use lambdas to split lists. While all of the answers are much appreciated, they're also a wonderful example of when lambdas do not simplify things.
Surely the below is sufficient
Stream it, collect with a grouping: this gives a Map of Object -> List, pull the values of the map and pass directly into whatever constructor (map.values() gives a Collection not a List).
Perhaps you can use something like that
Usage example
And as a result we have
If you REALLY need a lambda it can be done like this. Otherwise the previous answers are better.
Try this approach:
Also note that this code could be optimized, instead of:
use this one:
The requirement is a bit odd, but you could do:
You could probably streamline this by using the variant of
groupingBy
that takes amapSupplier
lambda, and supplying aSortedMap
. This should return anEntrySet
that iterates in order. I leave it as an exercise.What we're doing here is:
Map<Integer,Object>
using a counter to group. The counter is held in a single-element array because the lambda can only use local variables if they'refinal
.Integer
key.Stream::map()
to convert the stream ofMap.Entry<Integer,Object>
into a stream ofObject
values.This doesn't benefit from any "free" parallelisation. It has a memory overhead in the intermediate
Map
. It's not particularly easy to read.However, I wouldn't do this, just for the sake of using a lambda. I would do something like:
(Yours had a defensive copy
new ArrayList<>(listToSplit.subList(...))
. I've not duplicated it because it's not always necessary - for example if the input list is unmodifiable and the output lists aren't intended to be modifiable. But do put it back in if you decide you need it in your case.)This will be extremely fast on any in-memory list. You're very unlikely to want to parallelise it.
Alternatively, you could write your own (unmodifiable) implementation of
List
that's a view over the underlyingList<Object>
:Again, it's up to you whether you want to make defensive copies here.
This will be have equivalent big-O access time to the underlying list.