I want to group elements of a list. I'm currently doing it this way:
public static <E> List<List<E>> group(final List<E> list, final GroupFunction<E> groupFunction) {
List<List<E>> result = Lists.newArrayList();
for (final E element : list) {
boolean groupFound = false;
for (final List<E> group : result) {
if (groupFunction.sameGroup(element, group.get(0))) {
group.add(element);
groupFound = true;
break;
}
}
if (! groupFound) {
List<E> newGroup = Lists.newArrayList();
newGroup.add(element);
result.add(newGroup);
}
}
return result;
}
public interface GroupFunction<E> {
public boolean sameGroup(final E element1, final E element2);
}
Is there a better way to do this, preferably by using guava?
Sure it is possible, and even easier with Guava :) Use
Multimaps.index(Iterable, Function)
:If you give concrete use case it would be easier to show it in action.
Example from docs:
prints
In your case if GroupFunction is defined as:
then it would translate to:
which is possible
stringLengthFunction
implementation used in Guava's example.Finally, in Java 8, whole snippet could be even simpler, as lambas and method references are concise enough to be inlined:
For pure Java 8 (no Guava) example using
Collector.groupingBy
see Jeffrey Bosboom's answer, although there are few differences in that approach:ImmutableListMultimap
but ratherMap
withCollection
values,EDIT: If you don't care about indexed keys you can fetch grouped values:
what gives you
Lists<List<E>>
view which contents can be easily copied toArrayList
or just used as is, as you wanted in first place. Also note thatindexed.get(key)
isImmutableList
.EDIT 2: As Petr Gladkikh mentions in comment below, if
Collection<List<E>>
is enough, above example could be simpler:Collector.groupingBy
from the Java 8 streams library provides the same functionality as Guava'sMultimaps.index
. Here's the example in Xaerxess's answer, rewritten to use Java 8 streams:This will print
If you want to combine the values with the same key in some other way than creating a list, you can use the overload of
groupingBy
that takes another collector. This example concatenates the strings with a delimiter:This will print
If you have a large list or your grouping function is expensive, you can go parallel using
parallelStream
and a concurrent collector.This may print (the order is no longer deterministic)
The easiest and simplest way would be using: Lamdaj grouping feature
The above example can be re-written:
With Java 8, Guava and few helper functions you can implement grouping with custom Comparator
Example