Reputation: 1043
Apologies if this has been answered elsewhere, but I have yet to find a good answer!
I have a Set
of objects that I need to split by their underlying class
type, into a Set
for each (obviously this means that each object in the initial set will only appear in one of the new Set
objects).
My current approach to this is as follows:
public static Map<Class,Set<Foo>> splitByClass(Set<Foo> foos) {
// Create a map for the result
Map<Class,Set<Foo>> FooMap = new HashMap<Class,Set<Foo>>();
for (Foo foo: foos) {
Class type = foo.getClass();
// If a set for this key exists, add the item to that.
if (FooMap.containsKey(type)) {
FooMap.get(type).add(foo);
} else {
// Otherwise make a new set, add the item and the set to the map.
Set<Foo> set = new HashSet<Foo>();
set.add(foo);
FooMap.put(type, set);
}
}
return FooMap;
}
My question: Is there a more generic way to split a Set
into subsets, based on some evaluation method such as checking Class type?
Upvotes: 2
Views: 1824
Reputation: 299048
You can use a Guava Multimap
, it will make life a lot simpler:
Multimap<Class<? extends Foo>, Foo> mmap = HashMultimap.create();
for (Foo foo : foos) {
mmap.put(foo.getClass(), foo);
}
return mmap;
This code is pretty much equivalent to your above code, except that you must change the return type to Multimap<Class<? extends Foo>, Foo>
.
And here's a generic version that works with any supplied interface type:
public static <X> Multimap<Class<X>, X> splitByClass(
final Iterable<? extends X> implementations, final Class<X> interfaceType) {
final Multimap<Class<X>, X> mmap = HashMultimap.create();
for (final X implementation : implementations) {
@SuppressWarnings("unchecked")
// this should be safe:
final Class<X> implementationType = (Class<X>) implementation.getClass();
mmap.put(implementationType, implementation);
}
return mmap;
}
Upvotes: 2