Java tutorial
/* * @(#)Maps2.java Jul 31, 2011 * * Copyright 2010 Andrew Phillips. * * ==================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. * ==================================================================== */ package ext.deployit.community.cli.mustachify.collect; import static com.google.common.base.Functions.forMap; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Predicates.notNull; import static com.google.common.collect.ImmutableMap.copyOf; import static com.google.common.collect.Maps.filterValues; import static com.google.common.collect.Maps.newHashMap; import static com.google.common.collect.Maps.newHashMapWithExpectedSize; import static com.google.common.collect.Maps.transformValues; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.annotation.Nonnull; import com.google.common.base.Function; import com.google.common.collect.Maps; import com.google.common.collect.Sets; /** * @author aphillips * @since Jul 31, 2011 * */ public class Maps2 { /** * Constructs a map with the given keys where values are generated by the * given function. Supports duplicate and {@code null} values, but * {@code null} keys are <em>not</em> allowed. * * @param <K> * the type of the keys * @param <V> * the type of the values * @param keys * the keys to be included in the map. Keys must be non- * <code>null</code> * @param valueFunction * the function that produces values for the keys * @return a map containing the keys from the given set with values which * are generated from the keys * @see Maps#uniqueIndex(Iterable, Function) */ public static @Nonnull <K, V> Map<K, V> fromKeys(@Nonnull Set<K> keys, @Nonnull Function<? super K, V> valueFunction) { // can't use ImmutableMap.Builder as we're allowing null values Map<K, V> result = newHashMapWithExpectedSize(keys.size()); for (K key : keys) { result.put(checkNotNull(key), valueFunction.apply(key)); } return result; } public static @Nonnull <K1, K2, V> Map<K2, V> transformKeys(@Nonnull Map<K1, V> fromMap, Function<? super K1, K2> function) { // will catch dups Map<K2, K1> newKeys = Maps.uniqueIndex(fromMap.keySet(), function); // replace each old key with its value using a lookup in the input map return transformValues(newKeys, forMap(fromMap)); } /** * Constructs a map that contains all unique, non-<code>null</code> values * from the input map as keys. The value for each key in the returned map is * the set of keys from the input map that contained that value (i.e. the * key in the returned map). * <p> * Keys in the input map with {@code null} values are <u>omitted</u> from the * returned map. * <p> * This operation is similar to the <em>reduce</em> step in a map-reduce algorithm, * hence the name. * <p> * Examples: * <ul> * <li>{"foo": 10, "bar": 10, "baz": 20} -> {10: {"foo", "bar"}, 20: {"baz"}} * <li>{"foo": 10, "bar": 15, "baz": null} -> {10: {"foo"}, 15: {"bar"}} * </ul> * * @param <K> * the type of the keys * @param <V> * the type of the values * @param fromMap * the map containing the value/key pairs to be inverted * @return a map containing, for every unique (according to * {@link Object#equals(Object) equals} value, an entry with that * value as the key and a set of all keys from the input map as the * value. All entries of the input map that have {@code null} values * are <u>omitted</u> from the returned map. */ public static @Nonnull <K, V> Map<V, Set<K>> reduce(@Nonnull Map<K, V> fromMap) { Map<V, Set<K>> inProgress = newHashMap(); for (Entry<K, V> entry : filterValues(fromMap, notNull()).entrySet()) { V value = entry.getValue(); if (!inProgress.containsKey(value)) { inProgress.put(value, Sets.<K>newHashSet()); } inProgress.get(value).add(entry.getKey()); } return copyOf(inProgress); } }