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 }