blob: 07ba25a2663d04612a671d5c71d08767ec70a875 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.collections;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.apache.commons.lang.builder.ToStringBuilder;
import java.util.*;
/**
* A map holding multiple items at each key (using ArrayList and HashMap).
*
* @author bratseth
*/
public class ListMap<K, V> {
private boolean frozen = false;
private Map<K, List<V>> map;
public ListMap() {
this(HashMap.class);
}
@SuppressWarnings("unchecked")
public ListMap(@SuppressWarnings("rawtypes") Class<? extends Map> implementation) {
try {
this.map = implementation.newInstance();
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
/** Puts an element into this. Multiple elements at the same position are added to the list at this key */
public void put(K key, V value) {
List<V> list = map.get(key);
if (list == null) {
list = new ArrayList<>();
map.put(key, list);
}
list.add(value);
}
public void removeAll(K key) {
map.remove(key);
}
public boolean removeValue(K key, V value) {
List<V> list = map.get(key);
if (list != null)
return list.remove(value);
else
return false;
}
/**
* Removes the value at the given index.
*
* @return the removed value
* @throws IndexOutOfBoundsException if there is no value at the given index for this key
*/
public V removeValue(K key, int index) {
List<V> list = map.get(key);
if (list != null)
return list.remove(index);
else
throw new IndexOutOfBoundsException("The list at '" + key + "' is empty");
}
/**
* Returns the List containing the elements with this key, or an empty list
* if there are no elements for this key. The list returned is unmodifiable.
*/
public List<V> get(K key) {
List<V> list = map.get(key);
if (list == null)
return ImmutableList.of();;
return ImmutableList.copyOf(list);
}
/** The same as get */
public List<V> getList(K key) {
return get(key);
}
/** Returns the entries of this. Entries will be unmodifiable if this is frozen. */
public Set<Map.Entry<K,List<V>>> entrySet() { return map.entrySet(); }
/** Returns the keys of this */
public Set<K> keySet() { return map.keySet(); }
/** Returns the list values of this */
public Collection<List<V>> values() { return map.values(); }
/**
* Irreversibly prevent changes to the content of this.
* If this is already frozen, this method does nothing.
*/
public void freeze() {
if (frozen) return;
for (Map.Entry<K,List<V>> entry : map.entrySet())
entry.setValue(ImmutableList.copyOf(entry.getValue()));
this.map = ImmutableMap.copyOf(this.map);
}
/** Returns whether this allows changes */
public boolean isFrozen() { return frozen; }
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
/** Returns the number of keys in this map */
public int size() { return map.size(); }
}
|