aQute.lib.collections.MultiMap Maven / Gradle / Ivy
package aQute.lib.collections;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class MultiMap extends LinkedHashMap> implements Map> {
private static final long serialVersionUID = 1L;
private final boolean noduplicates;
private final Class> keyClass;
private final Class> valueClass;
public MultiMap() {
this(false);
}
public MultiMap(boolean noduplicates) {
this.noduplicates = noduplicates;
keyClass = Object.class;
valueClass = Object.class;
}
public MultiMap(Class keyClass, Class valueClass, boolean noduplicates) {
this.noduplicates = noduplicates;
this.keyClass = keyClass;
this.valueClass = valueClass;
}
public MultiMap(Map> other) {
this();
for (java.util.Map.Entry> e : other.entrySet()) {
addAll(e.getKey(), e.getValue());
}
}
public MultiMap(MultiMap other) {
keyClass = other.keyClass;
valueClass = other.valueClass;
noduplicates = other.noduplicates;
for (java.util.Map.Entry> e : other.entrySet()) {
addAll(e.getKey(), e.getValue());
}
}
@SuppressWarnings("unchecked")
public boolean add(K key, V value) {
assert keyClass.isInstance(key);
assert valueClass.isInstance(value);
List set = get(key);
if (set == null) {
set = new ArrayList<>();
if (valueClass != Object.class) {
set = Collections.checkedList(set, (Class) valueClass);
}
put(key, set);
} else {
if (noduplicates) {
if (set.contains(value))
return false;
}
}
return set.add(value);
}
@SuppressWarnings("unchecked")
public boolean addAll(K key, Collection extends V> value) {
if (value == null)
return false;
assert keyClass.isInstance(key);
List set = get(key);
if (set == null) {
set = new ArrayList<>();
if (valueClass != Object.class) {
set = Collections.checkedList(set, (Class) valueClass);
}
put(key, set);
} else if (noduplicates) {
boolean r = false;
for (V v : value) {
assert valueClass.isInstance(v);
if (!set.contains(v))
r |= set.add(v);
}
return r;
}
return set.addAll(value);
}
public boolean addAll(Map> map) {
boolean added = false;
for (java.util.Map.Entry> e : map.entrySet()) {
added |= addAll(e.getKey(), e.getValue());
}
return added;
}
public boolean removeValue(K key, V value) {
assert keyClass.isInstance(key);
assert valueClass.isInstance(value);
List set = get(key);
if (set == null) {
return false;
}
boolean result = set.remove(value);
if (set.isEmpty())
remove(key);
return result;
}
public boolean removeAll(K key, Collection extends V> value) {
assert keyClass.isInstance(key);
List set = get(key);
if (set == null) {
return false;
}
boolean result = set.removeAll(value);
if (set.isEmpty())
remove(key);
return result;
}
public Iterator iterate(K key) {
assert keyClass.isInstance(key);
List set = get(key);
if (set == null)
return Collections. emptyList()
.iterator();
return set.iterator();
}
public Iterator all() {
return new Iterator() {
Iterator> master = values().iterator();
Iterator current = null;
@Override
public boolean hasNext() {
if (current == null || !current.hasNext()) {
if (master.hasNext()) {
current = master.next()
.iterator();
return current.hasNext();
}
return false;
}
return true;
}
@Override
public V next() {
return current.next();
}
@Override
public void remove() {
current.remove();
}
};
}
public Map flatten() {
Map map = new LinkedHashMap<>();
for (Map.Entry> entry : entrySet()) {
List v = entry.getValue();
if (v == null || v.isEmpty())
continue;
map.put(entry.getKey(), v.get(0));
}
return map;
}
public MultiMap transpose() {
MultiMap inverted = new MultiMap<>();
for (Map.Entry> entry : entrySet()) {
K key = entry.getKey();
List value = entry.getValue();
if (value == null)
continue;
for (V v : value)
inverted.add(v, key);
}
return inverted;
}
/**
* Return a collection with all values
*
* @return all values
*/
public List allValues() {
return new IteratorList<>(all());
}
}