com.cinchapi.concourse.util.Transformers.java Source code

Java tutorial

Introduction

Here is the source code for com.cinchapi.concourse.util.Transformers.java

Source

/*
 * Copyright (c) 2013-2016 Cinchapi Inc.
 * 
 * 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 com.cinchapi.concourse.util;

import java.lang.reflect.Array;
import java.util.AbstractSet;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import com.cinchapi.concourse.annotate.UtilityClass;
import com.google.common.base.Function;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
 * A collection of tools used to transform objects in a collection using a
 * transformation {@link Function}.
 * 
 * @author Jeff Nelson
 */
@UtilityClass
public final class Transformers {

    /**
     * Return an array whose content is equal to the content of {@code original}
     * after it has been transformed by {@code function}.
     * 
     * @param original
     * @param function
     * @param vClass - the class object for the type to which the items in
     *            {@code original} will be transformed
     * @return the transformed array
     */
    @SuppressWarnings("unchecked")
    public static <F, V> V[] transformArray(F[] original, Function<? super F, ? extends V> function,
            Class<V> vClass) {
        V[] transformed = (V[]) Array.newInstance(vClass, original.length);
        for (int i = 0; i < original.length; ++i) {
            F item = original[i];
            transformed[i] = function.apply(item);
        }
        return transformed;
    }

    /**
     * Return a Map whose keys are equal to the those in {@code original} after
     * it has been transformed by {@code function}.
     * <p>
     * <strong>WARNING:</strong> There is the potential for data loss in the
     * event that {@code function} returns duplicate transformed results for
     * items in {@code original}.
     * </p>
     * 
     * @param original
     * @param function
     * @return the transformed Map
     */
    public static <K, K2, V> Map<K2, V> transformMap(Map<K, V> original,
            Function<? super K, ? extends K2> function) {
        Map<K2, V> transformed = PrettyLinkedHashMap.newPrettyLinkedHashMap();
        for (Map.Entry<K, V> entry : original.entrySet()) {
            transformed.put(function.apply(entry.getKey()), entry.getValue());
        }
        return transformed;
    }

    /**
     * Transform the keys in {@code original} with the {@code keys} function
     * and each of the values with the {@code values} function and return the
     * result.
     * <p>
     * <strong>WARNING:</strong> There is the potential for data loss in the
     * event that {@code function} returns duplicate transformed results for
     * items in {@code original}.
     * </p>
     * 
     * @param original
     * @param keys
     * @param values
     * @return the transformed Map
     */
    public static <K, K2, V, V2> Map<K2, Set<V2>> transformMapSet(Map<K, Set<V>> original,
            Function<? super K, ? extends K2> keys, Function<? super V, ? extends V2> values) {
        Map<K2, Set<V2>> transformed = Maps.newLinkedHashMap();
        for (Map.Entry<K, Set<V>> entry : original.entrySet()) {
            transformed.put(keys.apply(entry.getKey()), transformSet(entry.getValue(), values));
        }
        return transformed;
    }

    /**
     * Transform each of the values in the {@code original} with the
     * {@code function}.
     * 
     * @param original
     * @param function
     * @return the transformed Map
     */
    public static <K, V, V2> Map<K, V2> transformMapValues(Map<K, V> original, Function<V, V2> function) {
        Map<K, V2> transformed = Maps.newLinkedHashMap();
        for (Map.Entry<K, V> entry : original.entrySet()) {
            transformed.put(entry.getKey(), function.apply(entry.getValue()));
        }
        return transformed;
    }

    /**
     * Return a new {@link Map} where the key and value of each entry is
     * transformed by the {@code keyFunction} and {@code valueFunction}
     * respectively.
     * 
     * @param original the original map in which the transformations are
     *            performed
     * @param keyFunction the function to transform each entry key
     * @param valueFunction the function to transform each entry value
     * @return the transformed {@link Map}
     */
    public static <K1, V1, K2, V2> Map<K2, V2> transformMapEntries(Map<K1, V1> original,
            Function<K1, K2> keyFunction, Function<V1, V2> valueFunction) {
        Map<K2, V2> transformed = Maps.newLinkedHashMap();
        for (Map.Entry<K1, V1> entry : original.entrySet()) {
            transformed.put(keyFunction.apply(entry.getKey()), valueFunction.apply(entry.getValue()));
        }
        return transformed;
    }

    /**
     * Populate a {@link Set} with the items in {@code original} after applying
     * {@code function}.
     * 
     * <p>
     * <strong>WARNING:</strong> There is the potential for data loss in the
     * event that {@code function} returns duplicate transformed results for
     * items in {@code original}.
     * </p>
     * 
     * @param original the {@link Set} to transform
     * @param function the transformation {@link Function}
     * @return the transformed Set
     */
    public static <F, V> Set<V> transformSet(Set<F> original, Function<? super F, ? extends V> function) {
        Set<V> transformed = Sets.newLinkedHashSetWithExpectedSize(original.size());
        for (F item : original) {
            transformed.add(function.apply(item));
        }
        return transformed;
    }

    /**
     * Return a {@link Set} that lazily populates a new set with items from the
     * {@code original} after applying the transformation {@code function}.
     * 
     * @param original the {@link Set} to transform
     * @param function the transformation {@link Function}
     * @return the transformed Set
     */
    public static <V1, V2> Set<V2> transformSetLazily(Set<V1> original, Function<V1, V2> function) {
        return new LazyTransformSet<V1, V2>(original, function);
    }

    /**
     * Transform the keys in {@code original} with the {@code keys} function
     * and each of the values with the {@code values} function and return the
     * map result that is sorted according to the {@code sorter}.
     * <p>
     * <strong>WARNING:</strong> There is the potential for data loss in the
     * event that {@code function} returns duplicate transformed results for
     * items in {@code original}.
     * </p>
     * 
     * @param original
     * @param keys
     * @param values
     * @param sorter
     * @return the transformed TreeMap
     */
    public static <K, K2, V, V2> Map<K2, Set<V2>> transformTreeMapSet(Map<K, Set<V>> original,
            Function<? super K, ? extends K2> keys, Function<? super V, ? extends V2> values,
            final Comparator<K2> sorter) {
        Map<K2, Set<V2>> transformed = Maps.newTreeMap(sorter);
        for (Map.Entry<K, Set<V>> entry : original.entrySet()) {
            transformed.put(keys.apply(entry.getKey()), transformSet(entry.getValue(), values));
        }
        return transformed;
    }

    /**
     * A {@link Set} that transform values from an original set of type
     * {@code V1} into values of type {@code V2} on-the-fly using a
     * transformation {@link Function}.
     * 
     * @author chandresh.pancholi
     *
     */
    public static class LazyTransformSet<V1, V2> extends AbstractSet<V2> {

        /**
         * A {@link Function} to transform values of type {@code V1} in the
         * {@code original} set to values of type {@code V2}.
         */
        private final Function<V1, V2> function;

        /**
         * The original set, whose values will be transformed lazily.
         */
        private final Set<V1> original;

        /**
         * Construct a new instance.
         * 
         * @param original
         * @param function
         */
        public LazyTransformSet(Set<V1> original, Function<V1, V2> function) {
            this.original = original;
            this.function = function;
        }

        @Override
        public Iterator<V2> iterator() {
            return new ReadOnlyIterator<V2>() {
                Iterator<V1> backing = original.iterator();

                @Override
                public boolean hasNext() {
                    return backing.hasNext();
                }

                @Override
                public V2 next() {
                    return function.apply(backing.next());
                }
            };
        }

        @Override
        public int size() {
            return original.size();
        }
    }

}