package com.googlecode.totallylazy; import com.googlecode.totallylazy.functions.Callables; import com.googlecode.totallylazy.functions.Curried2; import com.googlecode.totallylazy.functions.Function1; import com.googlecode.totallylazy.predicates.Predicate; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import static com.googlecode.totallylazy.Callers.call; import static com.googlecode.totallylazy.Pair.pair; import static com.googlecode.totallylazy.predicates.Predicates.where; import static com.googlecode.totallylazy.Sequences.sequence; public class Maps { public static <K, V> Sequence<Pair<K, V>> pairs(final Map<K, V> map) { return entries(map).map(Maps.<K, V>entryToPair()); } public static <K, V> Function1<Map<K, V>, Sequence<Map.Entry<K, V>>> entries(Class<K> keyType, Class<V> valueType) { return entries(); } public static <K, V> Function1<Map<K, V>, Sequence<Map.Entry<K, V>>> entries() { return Maps::entries; } public static <K, V> Sequence<Map.Entry<K, V>> entries(final Map<K, V> map) { return sequence(map.entrySet()); } public static <K, V> Map<K, V> map() { return new LinkedHashMap<K, V>(); } public static <K, V> Map<K, V> map(K key, V value) { return map(pair(key, value)); } public static <K, V> Map<K, V> map(K key1, V value1, K key2, V value2) { return map(pair(key1, value1), pair(key2, value2)); } public static <K, V> Map<K, V> map(K key1, V value1, K key2, V value2, K key3, V value3) { return map(pair(key1, value1), pair(key2, value2), pair(key3, value3)); } public static <K, V> Map<K, V> map(K key1, V value1, K key2, V value2, K key3, V value3, K key4, V value4) { return map(pair(key1, value1), pair(key2, value2), pair(key3, value3), pair(key4, value4)); } public static <K, V> Map<K, V> map(K key1, V value1, K key2, V value2, K key3, V value3, K key4, V value4, K key5, V value5) { return map(pair(key1, value1), pair(key2, value2), pair(key3, value3), pair(key4, value4), pair(key5, value5)); } public static <K, V> Map<K, V> map(final Pair<? extends K, ? extends V> first) { return map(sequence(first)); } public static <K, V> Map<K, V> map(final Pair<? extends K, ? extends V> first, final Pair<? extends K, ? extends V> second) { return map(sequence(first, second)); } public static <K, V> Map<K, V> map(final Pair<? extends K, ? extends V> first, final Pair<? extends K, ? extends V> second, final Pair<? extends K, ? extends V> third) { return map(sequence(first, second, third)); } public static <K, V> Map<K, V> map(final Pair<? extends K, ? extends V> first, final Pair<? extends K, ? extends V> second, final Pair<? extends K, ? extends V> third, final Pair<? extends K, ? extends V> fourth) { return map(sequence(first, second, third, fourth)); } public static <K, V> Map<K, V> map(final Pair<? extends K, ? extends V> first, final Pair<? extends K, ? extends V> second, final Pair<? extends K, ? extends V> third, final Pair<? extends K, ? extends V> fourth, final Pair<? extends K, ? extends V> fifth) { return map(sequence(first, second, third, fourth, fifth)); } @SafeVarargs public static <K, V> Map<K, V> map(final Pair<? extends K, ? extends V>... entries) { return map(sequence(entries)); } @SafeVarargs public static <K, V> Map<K, V> map(final Map<K, V> seed, final Pair<? extends K, ? extends V>... entries) { return map(seed, sequence(entries)); } public static <K, V> Map<K, V> map(final Iterable<? extends Pair<? extends K, ? extends V>> entries) { return map(new LinkedHashMap<K, V>(), entries); } public static <K, V> Map<K, V> map(final Map<K, V> seed, final Iterable<? extends Pair<? extends K, ? extends V>> entries) { return map(seed, entries.iterator()); } public static <K, V> Map<K, V> map(final Iterator<? extends Pair<? extends K, ? extends V>> entries) { return map(new LinkedHashMap<K, V>(), entries); } public static <K, V> Map<K, V> map(final Map<K, V> seed, final Iterator<? extends Pair<? extends K, ? extends V>> entries) { while(entries.hasNext()){ Pair<? extends K, ? extends V> entry = entries.next(); seed.put(entry.first(), entry.second()); } return seed; } public static <T, Key> Map<Key, T> map(final Iterator<? extends T> iterator, final Function1<? super T, ? extends Key> callable) { return map(new LinkedHashMap<Key, T>(), iterator, callable); } public static <T, Key> Map<Key, T> map(final Map<Key, T> seed, final Iterator<? extends T> iterator, final Function1<? super T, ? extends Key> callable) { while (iterator.hasNext()) { final T next = iterator.next(); final Key key = call(callable, next); seed.put(key, next); } return seed; } public static <T, Key> Map<Key, T> map(final Iterable<? extends T> iterable, final Function1<? super T, ? extends Key> callable) { return map(iterable.iterator(), callable); } public static <T, Key> Map<Key, T> map(final Map<Key, T> seed, final Iterable<? extends T> iterable, final Function1<? super T, ? extends Key> callable) { return map(seed, iterable.iterator(), callable); } public static <K, V> Map<K, List<V>> multiMap(final Pair<? extends K, ? extends V> first, final Pair<? extends K, ? extends V> second) { return multiMap(sequence(first, second)); } public static <K, V> Map<K, List<V>> multiMap(final Pair<? extends K, ? extends V> first, final Pair<? extends K, ? extends V> second, final Pair<? extends K, ? extends V> third) { return multiMap(sequence(first, second, third)); } public static <K, V> Map<K, List<V>> multiMap(final Pair<? extends K, ? extends V> first, final Pair<? extends K, ? extends V> second, final Pair<? extends K, ? extends V> third, final Pair<? extends K, ? extends V> fourth) { return multiMap(sequence(first, second, third, fourth)); } public static <K, V> Map<K, List<V>> multiMap(final Pair<? extends K, ? extends V> first, final Pair<? extends K, ? extends V> second, final Pair<? extends K, ? extends V> third, final Pair<? extends K, ? extends V> fourth, final Pair<? extends K, ? extends V> fifth) { return multiMap(sequence(first, second, third, fourth, fifth)); } @SafeVarargs public static <K, V> Map<K, List<V>> multiMap(final Pair<? extends K, ? extends V>... entries) { return multiMap(sequence(entries)); } @SafeVarargs public static <K, V> Map<K, List<V>> multiMap(final Map<K, List<V>> seed, final Pair<? extends K, ? extends V>... entries) { return multiMap(seed, sequence(entries)); } public static <K, V> Map<K, List<V>> multiMap(final Iterable<? extends Pair<? extends K, ? extends V>> entries) { return multiMap(new LinkedHashMap<K, List<V>>(), entries); } public static <K, V> Map<K, List<V>> multiMap(final Map<K, List<V>> seed, final Iterable<? extends Pair<? extends K, ? extends V>> entries) { for (Pair<? extends K, ? extends V> entry : entries) { if (!seed.containsKey(entry.first())) { seed.put(entry.first(), new ArrayList<V>()); } seed.get(entry.first()).add(entry.second()); } return seed; } public static <T, Key> Map<Key, List<T>> multiMap(final Iterator<? extends T> iterator, final Function1<? super T, ? extends Key> callable) { return multiMap(new LinkedHashMap<Key, List<T>>(), iterator, callable); } public static <V, K> Map<K, List<V>> multiMap(final Map<K, List<V>> seed, final Iterator<? extends V> iterator, final Function1<? super V, ? extends K> callable) { while (iterator.hasNext()) { final V value = iterator.next(); final K key = call(callable, value); if (!seed.containsKey(key)) { seed.put(key, new ArrayList<V>()); } seed.get(key).add(value); } return seed; } public static <V, K> Map<K, List<V>> multiMap(final Iterable<? extends V> iterable, final Function1<? super V, ? extends K> callable) { return multiMap(iterable.iterator(), callable); } public static <V, K> Map<K, List<V>> multiMap(final Map<K, List<V>> seed, final Iterable<? extends V> iterable, final Function1<? super V, ? extends K> callable) { return multiMap(seed, iterable.iterator(), callable); } public static <K, V> Curried2<? super Map<K, List<V>>, ? super Pair<? extends K, ? extends V>, Map<K, List<V>>> asMultiValuedMap() { return (map, pair) -> { if (!map.containsKey(pair.first())) { map.put(pair.first(), new ArrayList<V>()); } map.get(pair.first()).add(pair.second()); return map; }; } public static <K, V> Curried2<? super Map<K, List<V>>, ? super Pair<? extends K, ? extends V>, Map<K, List<V>>> asMultiValuedMap(Class<K> key, Class<V> value) { return asMultiValuedMap(); } public static <K, V> Curried2<? super Map<K, V>, ? super Pair<K, V>, Map<K, V>> asMap() { return (map, pair) -> { map.put(pair.first(), pair.second()); return map; }; } public static <K, V> Curried2<? super Map<K, V>, ? super Pair<K, V>, Map<K, V>> asMap(Class<K> key, Class<V> value) { return asMap(); } public static <K, V> Function1<Pair<K, V>, Map.Entry<K, V>> pairToEntry() { return pair -> pair; } public static <K, V> Function1<Pair<K, V>, Map.Entry<K, V>> pairToEntry(final Class<K> keyClass, final Class<V> valueClass) { return pairToEntry(); } public static <K, V> Function1<Map.Entry<K, V>, Pair<K, V>> entryToPair() { return entry -> pair(entry.getKey(), entry.getValue()); } public static <K, V> Function1<Map.Entry<K, V>, Pair<K, V>> entryToPair(final Class<K> keyClass, final Class<V> valueClass) { return entryToPair(); } public static <K, V> Option<V> get(Map<K, V> map, K key) { return Option.option(map.get(key)); } public static <K, V> Option<V> find(Map<K, V> map, Predicate<? super K> predicate) { return pairs(map).find(where(Callables.<K>first(), predicate)).map(Callables.<V>second()); } public static <K, V> Map<K, V> filterKeys(Map<K, V> map, Predicate<? super K> predicate) { return map(pairs(map).filter(where(Callables.<K>first(), predicate))); } public static <K, V> Map<K, V> filterValues(Map<K, V> map, Predicate<? super V> predicate) { return map(pairs(map).filter(where(Callables.<V>second(), predicate))); } public static <K, V, NewK> Map<NewK, V> mapKeys(Map<K, V> map, Function1<? super K, ? extends NewK> transformer) { return map(pairs(map).map(Callables.<K, V, NewK>first(transformer))); } public static <K, V, NewV> Map<K, NewV> mapValues(Map<K, V> map, Function1<? super V, ? extends NewV> transformer) { return map(pairs(map).map(Callables.<K, V, NewV>second(transformer))); } public static <K, V> Map<K, V> fifoMap(final int maximumElements) { return new LinkedHashMap<K, V>(maximumElements) { protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { return size() > maximumElements; } }; } public static <K, V> Map<K, V> lruMap(final int maximumElements) { return new LinkedHashMap<K, V>(maximumElements, 1f, true) { protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { return size() > maximumElements; } }; } public static <K, V> Set<Map.Entry<K, V>> entrySet(final Iterable<? extends Pair<K, V>> map) { return sequence(map).map(Maps.<K, V>pairToEntry()).toSet(); } public static class functions { public static <K, V> Curried2<Map<K, V>, K, V> get() { return Map::get; } public static <K, V> Function1<K, V> getFrom(final Map<K, V> map) { return functions.<K,V>get().apply(map); } public static <K, V> Function1<Map<K, V>, V> valueFor(final K key) { return functions.<K,V>get().flip().apply(key); } public static <K, V> Function1<Map<K, V>, V> valueFor(final K key, final Class<V> vClass) { return valueFor(key); } } }