Is there some trick to convert HashMultiset<String>
to Map<String,Integer>
, except from iterating all the entries in the Set
?
Update: The Integer should represent the count of String in the multiset.
You can use Maps.asMap. With lambda expression (Java 8) it will be a one-liner:
Maps.asMap(multiset.elementSet(), elem -> multiset.count(elem));
In Java 7 and below:
final Multiset<String> multiset = HashMultiset.create();
Map<String, Integer> freqMap = Maps.asMap(multiset.elementSet(),
new Function<String, Integer>() {
@Override
public Integer apply(String elem) {
return multiset.count(elem);
}
});
Updated to java 8, here is what I found as the best answer (based on other answers):
public static <E> Map<E, Integer> convert(Multiset<E> multiset) {
return multiset.entrySet().stream().collect(
Collectors.toMap(x->x.getElement(),x->x.getCount()));
}
or:
public static <E> Map<E, Integer> convert(Multiset<E> multiset) {
return multiset.entrySet().stream().collect(
Collectors.toMap(Entry::getElement,Entry::getCount));
}
With Eclipse Collections you can use the method toMapOfItemToCount
on a Bag
(aka Multiset), which will return a Map
with a key of the same type in the Bag
and an Integer
count.
Note: I am a committer for Eclipse collections.
If you really want to avoid looping through the entries of the Multiset
, you can create a view of it as a Map:
public class MultisetMapView<E> implements Map<E, Integer> {
private Multiset<E> delegate;
public MultisetMapView(Multiset<E> delegate) {
this.delegate = delegate;
}
public int size() {
return delegate.size();
}
public boolean isEmpty() {
return delegate.isEmpty();
}
public boolean containsKey(Object key) {
return delegate.contains(key);
}
public boolean containsValue(Object value) {
throw new UnsupportedOperationException();
}
public Integer get(Object key) {
return delegate.count(key);
}
public Integer put(E key, Integer value) {
return delegate.setCount(key, value);
}
public Integer remove(Object key) {
int count = delegate.count(key);
delegate.remove(key);
return count;
}
public void putAll(Map<? extends E, ? extends Integer> m) {
for (Entry<? extends E, ? extends Integer> entry : m.entrySet()) {
delegate.setCount(entry.getKey(), entry.getValue());
}
}
public void clear() {
delegate.clear();
}
public Set<E> keySet() {
return delegate.elementSet();
}
public Collection<Integer> values() {
throw new UnsupportedOperationException();
}
public Set<java.util.Map.Entry<E, Integer>> entrySet() {
Set<java.util.Map.Entry<E, Integer>> entrySet = Sets.newHashSet();
for (E e : delegate) {
delegate.count(e);
entrySet.add(Maps.immutableEntry(e, delegate.count(e)));
}
return entrySet;
}
}
In my implementation, I declined to implement the containsValue
and values
methods, as these are not useful in the context. If desired, these could be implemented by looping through the entries and inspecting the count
of the elements encountered.
And again, you can see this working in this JUnit case:
@Test
public void testConvert() {
HashMultiset<String> hashMultiset = HashMultiset.create();
hashMultiset.add("a");
hashMultiset.add("a");
hashMultiset.add("a");
hashMultiset.add("b");
hashMultiset.add("c");
Map<String, Integer> map = new MultisetMapView<String>(hashMultiset);
assertEquals((Integer) 3, map.get("a"));
assertEquals((Integer) 1, map.get("b"));
assertEquals((Integer) 1, map.get("c"));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With