package arkref.ext.fig.basic; import java.util.*; public class MapUtils { // One-level hash maps public static <S, T> boolean contains(Map<S, T> map, S key) { return map != null && map.containsKey(key); } public static <S, T> T get(Map<S, T> map, S key, T defaultVal) { return map == null || !map.containsKey(key) ? defaultVal : map.get(key); } public static <S, T> T getMut(Map<S, T> map, S key, T defaultVal) { if(!map.containsKey(key)) { map.put(key, defaultVal); // Mutate return defaultVal; } return map.get(key); } public static <S,T> boolean putIfAbsent(Map<S,T> map, S key, T val) { if (map.containsKey(key)) return false; map.put(key, val); return true; } public static <S, T> void set(Map<S, T> map, S key, T val) { map.put(key, val); } public static <S> void incr(Map<S, Integer> map, S key, int dVal) { if(!map.containsKey(key)) map.put(key, dVal); else map.put(key, map.get(key) + dVal); } public static <S> void incr(Map<S, Integer> map, S key) { incr(map, key, 1); } public static <S> void incr(Map<S, Double> map, S key, double dVal) { if(!map.containsKey(key)) map.put(key, dVal); else map.put(key, map.get(key) + dVal); } // Two-level hash maps public static <S, T, U> boolean contains(Map<S, Map<T, U>> map, S key1, T key2) { if(map == null) return false; Map<T, U> m = map.get(key1); return m != null && m.containsKey(key2); } public static <S, T, U> U get(Map<S, Map<T, U>> map, S key1, T key2, U defaultVal) { if(map == null || !map.containsKey(key1)) return defaultVal; Map<T, U> m = map.get(key1); return m == null || !m.containsKey(key2) ? defaultVal : m.get(key2); } public static <S, T, U> U getMut(Map<S, Map<T, U>> map, S key1, T key2, U defaultVal) { Map<T, U> m = map.get(key1); if(m == null) { map.put(key1, m = new HashMap<T, U>()); m.put(key2, defaultVal); return defaultVal; } else if(!m.containsKey(key2)) { m.put(key2, defaultVal); return defaultVal; } return m.get(key2); } public static <S, T> void add(Map<S, Set<T>> map, S key1, T key2) { Set<T> s = map.get(key1); if(s == null) map.put(key1, s = new HashSet<T>()); s.add(key2); } public static <S, T, U> void set(Map<S, Map<T, U>> map, S key1, T key2, U val) { Map<T, U> m = map.get(key1); if(m == null) map.put(key1, m = new HashMap<T, U>()); m.put(key2, val); } public static <S, T> void incr(Map<S, Map<T, Integer>> map, S key1, T key2, int dVal) { Map<T, Integer> m = map.get(key1); if(m == null) { map.put(key1, m = new HashMap<T, Integer>()); m.put(key2, dVal); } else if(!m.containsKey(key2)) m.put(key2, dVal); else m.put(key2, m.get(key2) + dVal); } public static <S, T> void incr(Map<S, Map<T, Integer>> map, S key1, T key2) { incr(map, key1, key2, 1); } public static <S, T> void incr(Map<S, Map<T, Double>> map, S key1, T key2, double dVal) { Map<T, Double> m = map.get(key1); if(m == null) { map.put(key1, m = new HashMap<T, Double>()); m.put(key2, dVal); } else if(!m.containsKey(key2)) m.put(key2, dVal); else m.put(key2, m.get(key2) + dVal); } // Create a list if it doesn't exist public static <S, T> List<T> getListMut(Map<S, List<T>> map, S key) { List<T> list = map.get(key); if(list == null) map.put(key, list = new ArrayList()); return list; } // Hard operations // Wrapper for operations on maps and sets public static <S, T> T getHard(Map<S, T> map, S key) { T value = map.get(key); if(value == null) throw new RuntimeException("Doesn't contain key: " + key); return value; } public static <S, T> void putHard(Map<S, T> map, S key, T value) { if(map.containsKey(key)) throw new RuntimeException("Already contains key; " + key); map.put(key, value); } public static <S, T> T removeHard(Map<S, T> map, S key) { T value = map.remove(key); if(value == null) throw new RuntimeException("Doesn't contain key"); return value; } public static <S> void addHard(Set<S> set, S key) { if(set.contains(key)) throw new RuntimeException("Already contains key"); set.add(key); } public static <S> void removeHard(Set<S> set, S key) { if(!set.remove(key)) throw new RuntimeException("Doesn't contain key"); } // Print out the top k values a hash table sorted by descending value // Should only take O(k \log n) time, // but right now the implementation is slow public static <T> PriorityQueue<T> toPriorityQueue(Map<T, Double> map) { PriorityQueue<T> pq = new PriorityQueue<T>(); for(Map.Entry<T, Double> e : map.entrySet()) pq.add(e.getKey(), e.getValue()); return pq; } public static <T> PriorityQueue<T> toPriorityQueue(TDoubleMap<T> map) { PriorityQueue<T> pq = new PriorityQueue<T>(); for(TDoubleMap<T>.Entry e : map) pq.add(e.getKey(), e.getValue()); return pq; } public static <T> String topNToString(TDoubleMap<T> map, int numTop) { return topNToString(toPriorityQueue(map), numTop); } public static <T> String topNToString(Map<T, Double> map, int numTop) { return topNToString(toPriorityQueue(map), numTop); } public static <T> String topNToString(PriorityQueue<T> pq, int numTop) { StringBuilder sb = new StringBuilder(); sb.append('{'); for(Pair<T, Double> pair : getTopN(pq, numTop)) { Object key = pair.getFirst(); double value = pair.getSecond(); sb.append(' '); sb.append(key); sb.append(':'); sb.append(Fmt.D(value)); } if(pq.size() > numTop) sb.append(" ...("+(pq.size()-numTop)+ " more)"); sb.append(" }"); return sb.toString(); } // Return a list of the top n elements in the following structures public static <T> List<Pair<T, Double>> getTopN(Map<T, Double> map, int n) { return getTopN(toPriorityQueue(map), n); } public static <T> List<Pair<T, Double>> getTopN(TDoubleMap<T> map, int n) { return getTopN(toPriorityQueue(map), n); } public static <T> List<Pair<T, Double>> getTopN(PriorityQueue<T> pq, int n) { List<Pair<T, Double>> list = new ArrayList<Pair<T, Double>>(); for(int i = 0; i < n && pq.hasNext(); i++) { double priority = pq.getPriority(); T element = pq.next(); list.add(new Pair<T, Double>(element, priority)); } return list; } public static <K,M,V> Map<K,V> compose(Map<K,M> m1, Map<M,V> m2, Map<K,V> mapToFill) { for (Map.Entry<K,M> entry: m1.entrySet()) { V val = m2.get(entry.getValue()); if (val != null) mapToFill.put(entry.getKey(), val); } return mapToFill; } }