package org.hivedb.util.functional; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; /** * Operations on single or multi-dimensional maps which take multi-argument operators. These functions eliminate the need to * write messy embedded loops for standard navigation through multi-dimensional maps * @author Andy * */ public class Maps { public static<K,V> Map<K,V> newHashMap() { return new HashMap<K, V>(); } public static<I1,I2,V,R> Map<I1, Map<I2, Entry<V,R>>> dig( final Ternary<I1,I2,V,R> mapper, final Unary<I2,V> getV, final Unary<I1,Collection<I2>> getI2Collection, final Collection<I1> collection ) { return Transform.toMap( new Transform.IdentityFunction<I1>(), new Unary<I1, Map<I2, Entry<V,R>>>() { public Map<I2, Entry<V,R>> f(final I1 i1) { return Transform.toMap( new Transform.IdentityFunction<I2>(), new Unary<I2, Entry<V,R>>() { public Entry<V,R> f(I2 i2) { V v = getV.f(i2); return new Pair<V,R>( v, mapper.f(i1, i2, v)); }}, getI2Collection.f(i1)); }}, collection); } public static<I1,I2,V,R> Map<I1, Map<I2, Entry<V,R>>> digMap( final Ternary<I1,I2,V,R> mapper, Map<I1, Map<I2, V>> map) { return Transform.toMap( new Transform.MapToKeyFunction<I1,Map<I2, V>>(), new Unary<Entry<I1,Map<I2, V>>, Map<I2, Entry<V,R>>>() { public Map<I2, Entry<V,R>> f(final Entry<I1,Map<I2, V>> entry1) { return Transform.toMap( new Transform.MapToKeyFunction<I2,V>(), new Unary<Entry<I2, V>, Entry<V,R>>() { public Entry<V,R> f(Entry<I2, V> entry2) { return new Pair<V,R>( entry2.getValue(), mapper.f(entry1.getKey(), entry2.getKey(), entry2.getValue())); }}, entry1.getValue().entrySet()); }}, map.entrySet()); } /** * Given a 2 dimensional map whose last dimension is a collection, performs an operation with the given * Binary operator. * @param <I1> * @param <I2> * @param <R> * @param mapper Binary operator where the operator is given each combination of I1,I2 and returns R. You will likely * return I2 for R unless you actually are doing a tranform of each I2 value to R * @param map The 2 dimensional map whose last dimension is a collection of type I3 * @return a 2 dimensional map identical to map except with I2 values transformed to R values */ public static<I1,I2,R> Map<I1, Collection<R>> digMapToCollection( final Binary<I1,I2,R> mapper, Map<I1, Collection<I2>> map) { return Transform.toMap( new Transform.MapToKeyFunction<I1,Collection<I2>>(), new Unary<Entry<I1,Collection<I2>>, Collection<R>>() { public Collection<R> f(final Entry<I1,Collection<I2>> entryI1I2) { return Transform.map(new Unary<I2,R>() { public R f(I2 i2) { return mapper.f(entryI1I2.getKey(), i2); }}, entryI1I2.getValue()); }}, map.entrySet()); } /** * Given a 3 dimensional map whose last dimension is a collection, performs an operation with the given * Ternary operator. * @param <I1> * @param <I2> * @param <I3> * @param <R> * @param mapper Ternary operator where the operator is given each combination of I1,I2,I3 and returns R. You will likely * return I3 for R unless you actually are doing a tranform of each I3 value to R * @param map The 3 dimensional map whose last dimension is a collection of type I3 * @return a 3 dimensional map identical to map except with I3 values transformed to R values */ public static<I1,I2,I3,R> Map<I1, Map<I2, Collection<R>>> digMapToCollection( final Ternary<I1,I2,I3,R> mapper, Map<I1, Map<I2, Collection<I3>>> map) { return Transform.toMap( new Transform.MapToKeyFunction<I1,Map<I2,Collection<I3>>>(), new Unary<Entry<I1,Map<I2, Collection<I3>>>, Map<I2, Collection<R>>>() { public Map<I2, Collection<R>> f(final Entry<I1,Map<I2, Collection<I3>>> entryI1I2) { return Transform.toMap( new Transform.MapToKeyFunction<I2, Collection<I3>>(), new Unary<Entry<I2, Collection<I3>>, Collection<R>>() { public Collection<R> f(final Entry<I2, Collection<I3>> entryI2I3) { return Transform.map(new Unary<I3,R>() { public R f(I3 i3) { return mapper.f(entryI1I2.getKey(), entryI2I3.getKey(), i3); }}, entryI2I3.getValue()); }}, entryI1I2.getValue().entrySet()); }}, map.entrySet()); } /** * Given a 4 dimensional map whose last dimension is a collection, performs an operation with the given * Quaternary operator. * @param <I1> * @param <I2> * @param <I3> * @param <I4> * @param <R> * @param mapper Quaternary operator where the operator is given each combination of I1,I2,I3,14 and returns R. You will likely * return I4 for R unless you actually are doing a tranform of each I4 value to R * @param map The 4 dimensional map whose last dimension is a collection of type I4 * @return a 4 dimensional map identical to map except with I4 values transformed to R values */ public static<I1,I2,I3,I4,R> Map<I1, Map<I2, Map<I3, Collection<R>>>> digMapToCollection( final Quaternary<I1,I2,I3,I4,R> mapper, Map<I1, Map<I2, Map<I3, Collection<I4>>>> map) { return Transform.toMap( new Transform.MapToKeyFunction<I1,Map<I2, Map<I3,Collection<I4>>>>(), new Unary<Entry<I1,Map<I2, Map<I3,Collection<I4>>>>, Map<I2, Map<I3,Collection<R>>>>() { public Map<I2, Map<I3,Collection<R>>> f(final Entry<I1,Map<I2, Map<I3,Collection<I4>>>> entryI1I2) { return Transform.toMap( new Transform.MapToKeyFunction<I2, Map<I3,Collection<I4>>>(), new Unary<Entry<I2, Map<I3,Collection<I4>>>, Map<I3,Collection<R>>>() { public Map<I3,Collection<R>> f(final Entry<I2, Map<I3,Collection<I4>>> entryI2I3) { return Transform.toMap( new Transform.MapToKeyFunction<I3, Collection<I4>>(), new Unary<Entry<I3,Collection<I4>>, Collection<R>>() { public Collection<R> f(final Entry<I3,Collection<I4>> entryI3I4) { return Transform.map(new Unary<I4,R>() { public R f(I4 i4) { return mapper.f(entryI1I2.getKey(), entryI2I3.getKey(), entryI3I4.getKey(), i4); }}, entryI3I4.getValue()); }}, entryI2I3.getValue().entrySet()); }}, entryI1I2.getValue().entrySet()); }}, map.entrySet()); } public static<T> Map<Integer, T> hashCodeMap(Collection<T> items) { return Transform.toMap(new Unary<T, Integer>(){ public Integer f(T item) { return item.hashCode(); }}, new Transform.IdentityFunction<T>(), items); } public static<T> Map<Integer, T> hashCodeMap(T... items) { return hashCodeMap(Arrays.asList(items)); } }