I'm looking for a clever way to do the following operation:
Take a list of numbers:
1, 2, 3, 4, 5, 12, 13, 14, 19
and compact it into a string like so:
1-5, 12-14, 19
With the following rule: only compress into a range (i.e. use a dash) when the count of numbers in the range is 3 or more.
I.e.: 1, 2, 4, 5 would result in: 1, 2, 4, 5 and NOT: 1-2, 4-5
I can only think about a custom collector... You can obviously create a method that would return this collector and the code would be really compact in this case, provided that the collector is hidden via a static factory method.
Notice how the combiner
is doing basically nothing, not good for parallel coding. I'm still trying to think of a good way to provide an implementation for it.
List<String> result = IntStream.of(1, 2, 3, 4, 5, 12, 13, 14, 19)
.boxed()
.collect(Collector.of(
() -> {
List<List<Integer>> list = new ArrayList<>();
list.add(new ArrayList<>());
return list;
},
(list, x) -> {
List<Integer> inner = list.get(list.size() - 1);
if (inner.size() == 0) {
inner.add(x);
} else {
int lastElement = inner.get(inner.size() - 1);
if (lastElement == x - 1) {
inner.add(x);
} else {
List<Integer> oneMore = new ArrayList<>();
oneMore.add(x);
list.add(oneMore);
}
}
},
(left, right) -> {
throw new IllegalArgumentException("No parallel!");
},
list -> {
return list.stream()
.map(inner -> {
if (inner.size() > 1) {
return inner.get(0) + "-" + inner.get(inner.size() - 1);
}
return "" + inner.get(0);
}).collect(Collectors.toList());
}));
System.out.println(result);