001 package ezvcard.util;
002
003 import java.util.ArrayList;
004 import java.util.Collection;
005 import java.util.LinkedHashMap;
006 import java.util.List;
007 import java.util.Map;
008 import java.util.Set;
009
010 /*
011 Copyright (c) 2012, Michael Angstadt
012 All rights reserved.
013
014 Redistribution and use in source and binary forms, with or without
015 modification, are permitted provided that the following conditions are met:
016
017 1. Redistributions of source code must retain the above copyright notice, this
018 list of conditions and the following disclaimer.
019 2. Redistributions in binary form must reproduce the above copyright notice,
020 this list of conditions and the following disclaimer in the documentation
021 and/or other materials provided with the distribution.
022
023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
024 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
025 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
026 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
027 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
028 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
029 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
030 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
031 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
032 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
033
034 The views and conclusions contained in the software and documentation are those
035 of the authors and should not be interpreted as representing official policies,
036 either expressed or implied, of the FreeBSD Project.
037 */
038
039 /**
040 * A multimap that uses {@link List} objects to store its values.
041 *
042 * <p>
043 * The internal {@link Map} implementation is a {@link LinkedHashMap} that uses
044 * {@link ArrayList} for its values.
045 * </p>
046 * @author Michael Angstadt
047 * @param <K> the key
048 * @param <V> the value
049 */
050 public class ListMultimap<K, V> {
051 private final Map<K, List<V>> map = new LinkedHashMap<K, List<V>>();
052
053 public ListMultimap() {
054 }
055
056 /**
057 * Copy constructor.
058 * @param orig the multimap to copy from
059 */
060 public ListMultimap(ListMultimap<K, V> orig) {
061 for (Map.Entry<K, List<V>> entry : orig.map.entrySet()) {
062 List<V> values = new ArrayList<V>(entry.getValue());
063 map.put(entry.getKey(), values);
064 }
065 }
066
067 /**
068 * Adds a value to the multimap.
069 * @param key the key
070 * @param value the value
071 */
072 public void put(K key, V value) {
073 List<V> values = map.get(key);
074 if (values == null) {
075 values = new ArrayList<V>();
076 map.put(key, values);
077 }
078 values.add(value);
079 }
080
081 /**
082 * Gets the values associated with the key.
083 * @param key the key
084 * @return the list of values or empty list if the key doesn't exist
085 */
086 public List<V> get(K key) {
087 List<V> values = map.get(key);
088 if (values == null) {
089 values = new ArrayList<V>();
090 }
091 return values;
092 }
093
094 /**
095 * Removes all the values associated with a key
096 * @param key the key to remove
097 * @return the removed values
098 */
099 public List<V> remove(K key) {
100 return map.remove(key);
101 }
102
103 /**
104 * Removes a particular value.
105 * @param key the key
106 * @param value the value to remove
107 * @return true if the multimap contained the value, false if not
108 */
109 public boolean remove(K key, V value) {
110 List<V> values = map.get(key);
111 if (values != null) {
112 return values.remove(value);
113 }
114 return false;
115 }
116
117 /**
118 * Returns all the keys.
119 * @return all the keys
120 */
121 public Set<K> keySet() {
122 return map.keySet();
123 }
124
125 /**
126 * Returns all the values.
127 * @return all the values
128 */
129 public Collection<V> values() {
130 Collection<V> list = new ArrayList<V>();
131 for (List<V> value : map.values()) {
132 list.addAll(value);
133 }
134 return list;
135 }
136
137 /**
138 * Determines if the multimap is empty or not.
139 * @return true if it's empty, false if not
140 */
141 public boolean isEmpty() {
142 return size() == 0;
143 }
144
145 /**
146 * Returns the number of values in the map.
147 * @return the number of values
148 */
149 public int size() {
150 int size = 0;
151 for (List<V> value : map.values()) {
152 size += value.size();
153 }
154 return size;
155 }
156
157 /**
158 * Gets the underlying {@link Map} object.
159 * @return the underlying {@link Map} object
160 */
161 public Map<K, List<V>> getMap() {
162 return map;
163 }
164 }