Since the release versions have two digits, the input list may be grouped by the prefix (thus getting a map of String, List<String>) using Collectors.groupingBy and then the list of the versions is sorted using Collectors.collectingAndThen:
List<List<String>> versions = new ArrayList<>(
list
.stream()
.collect(Collectors.groupingBy(
str -> str.substring(0, str.lastIndexOf('.')),
Collectors.collectingAndThen(
Collectors.toList(),
(List<String> lst) -> { lst.sort(String::compareTo); return lst; }
)
))
.values() // Collection<List<String>>
);
versions.forEach(System.out::println);
Output:
[1.0.0, 1.0.1, 1.0.2]
[2.0.0]
[3.0.0, 3.0.1]
[1.5.0, 1.5.1]
[2.5.0]
[3.5.0]
The code above assumes the format of the release part in the version always has at least two dots (major and minor versions).
If some versions may not comply with the initial format (e.g., there are 0.1 or 1.0.2.1), the following grouping condition should work fine:
str -> str.substring(0, str.indexOf('.', str.indexOf('.') + 1) + 1), - the release prefix is assumed to contain at least 1 dot . and at most two dots.
Example Groovy implementation:
def list = ["3.5.0", "3.0.1", "3.0.0", "2.5.0", "2.0.0", "1.5.1", "1.5.0", "1.0.2", "1.0.1", "1.0.0"]
def versions = new ArrayList<> (list.groupBy {
it.substring(0, it.lastIndexOf('.'))
}.values())
.each { it.sort() }
versions.each {println it }
Output:
[3.5.0]
[3.0.0, 3.0.1]
[2.5.0]
[2.0.0]
[1.5.0, 1.5.1]
[1.0.0, 1.0.1, 1.0.2]
Update
The following Groovy code fixes sorting issues and also removes the highest version as well as the empty results:
def list = ["3.5.0", "3.0.1", "3.0.0", "2.5.0", "2.0.0", "1.5.1", "1.5.0", "1.0.1", "1.0.0",
"1.0.10", "1.0.11", "1.0.2", "1.0.3", "1.0.4", "1.0.5", "1.0.6", "1.0.7", "1.0.8", "1.0.9"]
def versions = new ArrayList<> (
list
.sort() // sort initial list
.groupBy {
it.substring(0, it.lastIndexOf('.'))
}.values()
)
.each { it.sort{ a,b -> Integer.compare(
Integer.parseInt(a.substring(a.lastIndexOf('.') + 1)),
Integer.parseInt(b.substring(b.lastIndexOf('.') + 1))
)}.removeAt(it.size() - 1) }
versions.removeIf { it.empty } // remove empty sublists if any found
versions.each {println it }
Output
[1.0.0, 1.0.1, 1.0.2, 1.0.3, 1.0.4, 1.0.5, 1.0.6, 1.0.7, 1.0.8, 1.0.9, 1.0.10]
[1.5.0]
[3.0.0]