/************************************************************************* * Copyright 2009-2014 Eucalyptus Systems, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need * additional information or have any questions. ************************************************************************/ package com.eucalyptus.util; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.function.BiFunction; import javax.annotation.Nonnull; import javax.annotation.Nullable; import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.FluentIterable; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; /** * Utility functions for collections */ public class CollectionUtils { /** * Apply the given function for each item in the iterable. * * <p>This method is an anti-pattern as the function is really an effect (it * can only be useful for its side effect)</p> * * @param iterable The iterable * @param function The function to apply * @param <T> The iterable type */ public static <T> void each( final Iterable<T> iterable, final Function<? super T,?> function ) { Iterables.size( Iterables.transform( iterable, function ) ); // transform is lazy } /** * Apply the given predicate for each item in the iterable. * * <p>This method is an anti-pattern as the predicate is really an effect (it * can only be useful for its side effect)</p> * * @param iterable The iterable * @param predicate The predicate to apply * @param <T> The iterable type */ public static <T> void each( final Iterable<T> iterable, final Predicate<? super T> predicate ) { each( iterable, Functions.forPredicate( predicate ) ); } /** * Create a fluent iterable for the given iterable. * * @param iterable The possibly null iterable * @param <T> The iterable type * @return the FluentIterable */ @Nonnull public static <T> FluentIterable<T> fluent( @Nullable final Iterable<T> iterable ) { return FluentIterable.from( iterable == null ? Collections.<T>emptyList( ) : iterable ); } /** * Predicate for collections containing the given item. * * @param item The required item * @param <CIT> The item type * @param <CT> The collection type * @return A collection matching predicate */ public static <CIT,CT extends Collection<? super CIT>> Predicate<CT> contains( final CIT item ) { return new Predicate<CT>( ){ @Override public boolean apply( @Nullable final CT collection ) { return collection != null && collection.contains( item ); } }; } /** * Convenience method for a predicate on a property value. * * @param propertyValue The property value to match * @param propertyFunction The function to extract the property * @param <T> The predicate type * @param <PT> The property type * @return A predicate that extracts a value to compare with the given value. */ public static <T,PT> Predicate<T> propertyPredicate( final PT propertyValue, final Function<T,PT> propertyFunction ) { return Predicates.compose( Predicates.equalTo( propertyValue ), propertyFunction ); } /** * Convenience method for a predicate on a property value. * * @param propertyValues The property values to match * @param propertyFunction The function to extract the property * @param <T> The predicate type * @param <PT> The property type * @return A predicate that extracts a value to compare with the given values. */ public static <T,PT> Predicate<T> propertyPredicate( final Collection<PT> propertyValues, final Function<T,PT> propertyFunction ) { return Predicates.compose( Predicates.in( propertyValues ), propertyFunction ); } /** * Convenience method for a predicate on a property value. * * @param propertyValue The property value to match * @param propertyFunction The function to extract the collection property * @param <T> The predicate type * @param <PCT> The property collection type * @param <PIT> The property collection item type * @return A predicate that extracts a value to compare with the given value. */ public static <T,PIT, PCT extends Collection<? super PIT>> Predicate<T> propertyContainsPredicate( final PIT propertyValue, final Function<T,PCT> propertyFunction ) { return Predicates.compose( contains( propertyValue ), propertyFunction ); } public static <T> CompatFunction<T,List<T>> listUnit() { return new CompatFunction<T,List<T>>() { @SuppressWarnings( "unchecked" ) @Override public List<T> apply( final T t ) { return t == null ? Lists.<T>newArrayList() : Lists.newArrayList( t ); } }; } public static <T> CompatFunction<List<List<T>>,List<T>> listJoin() { return new CompatFunction<List<List<T>>,List<T>>() { @SuppressWarnings( "unchecked" ) @Override public List<T> apply( final List<List<T>> t ) { return t == null ? Lists.<T>newArrayList() : Lists.newArrayList( Iterables.concat( t ) ); } }; } public static <T> CompatFunction<T,Optional<T>> optionalUnit( ) { return new CompatFunction<T,Optional<T>>() { @Override public Optional<T> apply( final T t ) { return Optional.fromNullable( t ); } }; } public static <T> Function<Optional<T>,T> optionalOrNull() { return new Function<Optional<T>,T>( ) { @Nullable @Override public T apply( final Optional<T> optional ) { return optional == null ? null : optional.orNull( ); } }; } public static <T> Function<Optional<T>,T> optionalOr( final T value ) { return new Function<Optional<T>,T>( ) { @Nullable @Override public T apply( final Optional<T> optional ) { return optional == null ? null : optional.or( value ); } }; } /** * Unchecked cast function. * * @param target The type to cast to * @param <F> The source type * @param <T> The result type * @return A function that casts to the given type * @see Predicates#instanceOf(Class) * @see Iterables#filter(Iterable, Class) */ public static <F,T> Function<F,T> cast( final Class<T> target ) { //noinspection unchecked return (Function<F,T>) Functions.identity( ); } /** * Reduce a collection using an initial value and a reduction function. * * @param iterable The iterable to be reduced * @param initialValue The initial value * @param reducer The reduction function * @param <T> The result type * @param <I> The iterable type * @return The final value */ public static <T,I> T reduce( final Iterable<? extends I> iterable, final T initialValue, final Function<T,Function<I,T>> reducer ) { T value = initialValue; for ( I item : iterable ) { value = reducer.apply( value ).apply( item ); } return value; } /** * Reduce a collection using an initial value and a reduction function. * * @param iterable The iterable to be reduced * @param initialValue The initial value * @param reducer The reduction function * @param <T> The result type * @param <I> The iterable type * @return The final value */ public static <T,I> T reduce( final Iterable<? extends I> iterable, final T initialValue, final BiFunction<T,I,T> reducer ) { T value = initialValue; for ( I item : iterable ) { value = reducer.apply( value, item ); } return value; } public static <I,K,V> Map<K,V> putAll( final Iterable<? extends I> iterable, final Map<K,V> targetMap, final Function<? super I, K> keyFunction, final Function<? super I, V> valueFunction ) { if ( iterable != null ) for ( final I item : iterable ) { targetMap.put( keyFunction.apply( item ), valueFunction.apply( item ) ); } return targetMap; } public static <I,K,V> Multimap<K,V> putAll( final Iterable<? extends I> iterable, final Multimap<K,V> targetMap, final Function<? super I, K> keyFunction, final Function<? super I, V> valueFunction ) { if ( iterable != null ) for ( final I item : iterable ) { targetMap.put( keyFunction.apply( item ), valueFunction.apply( item ) ); } return targetMap; } /** * Transform the given map, ignoring mapped entries with null keys or values. * * <p>WARNING! if the transform produces duplicate keys entries will be * overwritten.</p> * * @param map The map to transform * @param targetMap The result map * @param keyFunction The key transform * @param valueFunction The value transform * @param <K1> The source key type * @param <V1> The source value type * @param <K2> The target key type * @param <V2> The target value type * @return The supplied target map */ public static <K1,V1,K2,V2> Map<K2,V2> transform( final Map<K1,V1> map, final Map<K2,V2> targetMap, final Function<? super K1, K2> keyFunction, final Function<? super V1, V2> valueFunction ) { if ( map != null ) for ( final Map.Entry<K1,V1> entry : map.entrySet( ) ) { final K2 targetKey = keyFunction.apply( entry.getKey( ) ); final V2 targetValue = valueFunction.apply( entry.getValue( ) ); if ( targetKey != null && targetValue != null ) { targetMap.put( targetKey, targetValue ); } } return targetMap; } /** * Min function suitable for use with reduce. * * @return The min function. */ public static NonNullFunction<Integer,Function<Integer,Integer>> min() { return new NonNullFunction<Integer,Function<Integer,Integer>>() { @Nonnull @Override public Function<Integer, Integer> apply( final Integer integer1 ) { return new Function<Integer, Integer>(){ @Override public Integer apply( final Integer integer2 ) { return Math.min( integer1, integer2 ); } }; } }; } /** * Min function suitable for use with reduce. * * @return The long min function. */ public static NonNullFunction<Long,Function<Long,Long>> lmin() { return new NonNullFunction<Long,Function<Long,Long>>() { @Nonnull @Override public Function<Long, Long> apply( final Long long1 ) { return new Function<Long, Long>(){ @Override public Long apply( final Long long2 ) { return Math.min( long1, long2 ); } }; } }; } /** * Count function suitable for use with reduce. * * @param evaluator Predicate matching items to be counted. * @param <I> The evaluated type * @return The count function. */ public static <I> Function<Integer,Function<I,Integer>> count( final Predicate<? super I> evaluator ) { return sum( new Function<I,Integer>(){ @Override public Integer apply( @Nullable final I item ) { return evaluator.apply( item ) ? 1 : 0; } } ); } /** * Sum function suitable for use with reduce. * * @param evaluator Function to obtain an int from an I * @param <I> The evaluated type * @return The sum function. */ public static <I> Function<Integer,Function<I,Integer>> sum( final Function<I,Integer> evaluator ) { return new Function<Integer,Function<I,Integer>>() { @Override public Function<I, Integer> apply( final Integer sum ) { return new Function<I, Integer>() { @Override public Integer apply( final I item ) { return sum + evaluator.apply( item ); } }; } }; } /** * Function suitable for use with reduce that enforces a single item. * * @param <I> The evaluated type * @return The reduction function. */ public static <I> Function<I,Function<I,I>> unique( ) { return new Function<I,Function<I,I>>( ) { @Override public Function<I, I> apply( final I item1 ) { return new Function<I, I>() { @Override public I apply( final I item2 ) { if ( item1 != null && item2 != null ) { throw new IllegalArgumentException( "Not unique" ); } return item1 == null ? item2 : item1; } }; } }; } /** * Function suitable for use with reduce that add to the initial collection. * * @param <I> The evaluated type * @return The reduction function. */ public static <IT,I extends Collection<IT>> Function<I,Function<I,I>> addAll( ) { return new Function<I,Function<I,I>>( ) { @Override public Function<I, I> apply( final I reduction ) { return new Function<I, I>() { @Override public I apply( final I collection ) { if ( collection != null ) { reduction.addAll( collection ); } return reduction; } }; } }; } /** * Flip parameter order for curried function. * * @param curried The function to flip * @param <F1> The first parameter type * @param <F2> The second parameter type * @param <T> The result type * @return The flipped function */ public static <F1,F2,T> NonNullFunction<F2,Function<F1,T>> flipCurried( final Function<F1,Function<F2,T>> curried ) { return new NonNullFunction<F2,Function<F1,T>>( ){ @Nonnull @Override public Function<F1, T> apply( @Nullable final F2 f2 ) { return new Function<F1, T>( ){ @Override public T apply( @Nullable final F1 f1 ) { //noinspection ConstantConditions return curried.apply( f1 ).apply( f2 ); } }; } }; } /** * Comparator function suitable for use with reduce. * * <p>Use with reduce to obtain a min or max value.</p> * * @param comparator The comparator to use * @param <T> The compared type * @return The comparator function. * @see com.google.common.collect.Ordering */ public static <T> Function<T,Function<T,T>> comparator( final Comparator<T> comparator ) { return new Function<T,Function<T,T>>() { @Override public Function<T, T> apply( final T t1 ) { return new Function<T,T>() { @Override public T apply( final T t2 ) { return comparator.compare( t1, t2 ) < 0 ? t1 : t2; } }; } }; } }