Arturo González Arturo González - 2 months ago 5x
Java Question

Java 8. Group a list of values into a list of ranges using Collectors

I need your help,

In Java 8 using Collectors groupingBy I need to group a list like this

ValueObject {id=1, value=2.0}
ValueObject {id=2, value=2.0}
ValueObject {id=3, value=2.0}
ValueObject {id=4, value=3.0}
ValueObject {id=5, value=3.0}
ValueObject {id=6, value=4.0}
ValueObject {id=7, value=4.0}
ValueObject {id=8, value=4.0}
ValueObject {id=9, value=4.0}
ValueObject {id=10, value=4.0}

in another one like this

GroupedObject {from=1, to=3, value=2.0}
GroupedObject {from=4, to=5, value=3.0}
GroupedObject {from=6, to=10, value=4.0}

Those are the definitions of the objects i'm using

public class ValueObject {

private int id;
private double value;

public String getId() {
return id;

public float getValue() {
return value;

public void setValue(float value) {
this.value = value;


public class GroupedObject {

private int from;
private int to;
private double value;

public int getFrom() {
return from;

public void setFrom(int from) {
this.from = from;

public int getTo() {
return to;

public void setTo(int to) { = to;

public double getValue() {
return value;

public void setValue(double value) {
this.value = value;


And this is how i'm doing it programmatically.

public class Service {

public List<GroupedObject> groupToRange(List<ValueObject> list) {

List<GroupedObject> filtered = new ArrayList<>();

if (list.size() > 0) {

ValueObject current = list.get(0);
GroupedObject dto = new GroupedObject();

for (int i = 0; i < list.size(); i++) {
ValueObject vo = list.get(i);
if (vo.getValue() != current.getValue()) {


dto = new GroupedObject();
current = vo;

} else {
current = vo;
if (i == list.size() - 1) {
return filtered;


this is the unit test

public class ServiceTest {

Service service = new Service();

public void testgGoupToRange() {

List entryList = new ArrayList<>();

entryList.add(new ValueObject(1, 2.0));
entryList.add(new ValueObject(2, 2.0));
entryList.add(new ValueObject(3, 2.0));
entryList.add(new ValueObject(4, 3.0));
entryList.add(new ValueObject(5, 3.0));
entryList.add(new ValueObject(6, 4.0));
entryList.add(new ValueObject(7, 4.0));
entryList.add(new ValueObject(8, 4.0));
entryList.add(new ValueObject(9, 4.0));
entryList.add(new ValueObject(10, 4.0));

List responseList = service.groupToRange(entryList);

responseList.forEach(obj-> System.out.println(obj.toString()));

assertEquals(3, responseList.size());



I havn´t found a way of doing it whit java 8 and collectors


Here's what I came up with

List<ValueObject> values = Arrays.asList(new ValueObject(1, 2.0),
                                         new ValueObject(2, 2.0),
                                         new ValueObject(3, 3.0),
                                         new ValueObject(4, 4.0),
                                         new ValueObject(5, 4.0),
                                         new ValueObject(6, 4.0));
Map<Double, IntSummaryStatistics> groupedValues =

List<GroupedObject> groupedObjects = groupedValues.entrySet()
                                                  .map(groupedValue -> new GroupedObject(groupedValue.getValue().getMin(),

I'm pretty confident that there's a way to avoid the intermediary Map<Double, IntSummaryStatistics but I haven't figured it out yet. Will update if I do.

EDIT: See @Tunaki's answer for a 1 pass answer.

This is the output

[GroupedObject{from=4, to=6, value=4.0}, GroupedObject{from=1, to=2, value=2.0}, GroupedObject{from=3, to=3, value=3.0}]