/*
* Author: Alexis Cartier <alexcrt>
* Date : 24 déc. 2014
*/
package com.codepoetics.protonpack.maps;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
import static java.util.stream.Collectors.*;
/**
* A stream of {@code Map.Entry<K, V>}.
*/
public interface MapStream<K, V> extends Stream<Entry<K, V>> {
/**
* Construct a {@code MapStream<K, V>} from the map
* @param map - the map to build the stream from
* @param <K> - the type of the map keys
* @param <V> - the type of the map values
* @return a new {@code MapStream<K, V>}
*/
public static <K, V> MapStream<K, V> of(Map<K, V> map) {
return new DefaultMapStream<>(map.entrySet().stream());
}
/**
* Construct a {@code MapStream<K, V>} from the map
* @param maps - the map to build the stream from
* @param <K> - the type of the map keys
* @param <V> - the type of the map values
* @return a new {@code MapStream<K, V>}
*/
@SafeVarargs
public static <K, V> MapStream<K, V> ofMaps(Map<K, V>... maps) {
return new DefaultMapStream<>(Stream.of(maps).flatMap(m -> m.entrySet().stream()));
}
/**
* Construct a {@code MapStream<K, V>} from a single key-value pair
* @param key - the key
* @param value - the value
* @param <K> - the type of the map keys
* @param <V> - the type of the map values
* @return a new {@code MapStream<K, V>}
*/
public static <K, V> MapStream<K, V> of(K key, V value) {
return new DefaultMapStream<>(Stream.of(new SimpleImmutableEntry<>(key, value)));
}
/**
* Construct a {@code MapStream<K, V>} from a multiple key-value pairs
* @param key - key
* @param value - value
* @param key1 - key1
* @param value1 - value1
* @param <K> - the type of the map keys
* @param <V> - the type of the map values
* @return a new {@code MapStream<K, V>}
*/
public static <K, V> MapStream<K, V> of(K key, V value, K key1, V value1) {
return new DefaultMapStream<>(Stream.of(new SimpleImmutableEntry<>(key, value),
new SimpleImmutableEntry<>(key1, value1)));
}
/**
* Construct a {@code MapStream<K, V>} from a multiple key-value pairs
* @param key - key
* @param value - value
* @param key1 - key1
* @param value1 - value1
* @param key2 - key2
* @param value2 - value2
* @param <K> - the type of the map keys
* @param <V> - the type of the map values
* @return a new {@code MapStream<K, V>}
*/
public static <K, V> MapStream<K, V> of(K key, V value, K key1, V value1, K key2, V value2) {
return new DefaultMapStream<>(Stream.of(new SimpleImmutableEntry<>(key, value),
new SimpleImmutableEntry<>(key1, value1),
new SimpleImmutableEntry<>(key2, value2)));
}
/**
* Construct a {@code MapStream<K, V>} from a multiple key-value pairs
* @param key - key
* @param value - value
* @param key1 - key1
* @param value1 - value1
* @param key2 - key2
* @param value2 - value2
* @param key3 - key3
* @param value3 - value3
* @param <K> - the type of the map keys
* @param <V> - the type of the map values
* @return a new {@code MapStream<K, V>}
*/
public static <K, V> MapStream<K, V> of(K key, V value, K key1, V value1, K key2, V value2, K key3, V value3) {
return new DefaultMapStream<>(Stream.of(new SimpleImmutableEntry<>(key, value),
new SimpleImmutableEntry<>(key1, value1),
new SimpleImmutableEntry<>(key2, value2),
new SimpleImmutableEntry<>(key3, value3)));
}
/**
* Construct a {@code MapStream<K, V>} from a multiple key-value pairs
* @param key - key
* @param value - value
* @param key1 - key1
* @param value1 - value1
* @param key2 - key2
* @param value2 - value2
* @param key3 - key3
* @param value3 - value3
* @param key4 - key4
* @param value4 - value4
* @param <K> - the type of the map keys
* @param <V> - the type of the map values
* @return a new {@code MapStream<K, V>}
*/
public static <K, V> MapStream<K, V> of(K key, V value, K key1, V value1, K key2, V value2, K key3, V value3, K key4, V value4) {
return new DefaultMapStream<>(Stream.of(new SimpleImmutableEntry<>(key, value),
new SimpleImmutableEntry<>(key1, value1),
new SimpleImmutableEntry<>(key2, value2),
new SimpleImmutableEntry<>(key3, value3),
new SimpleImmutableEntry<>(key4, value4)));
}
/**
* Applies the mapping for each keys in the map. If your mapping function is not bijective,
* make sure you call {@code mergeKeys} or that you provide a merge function when calling
* {@code collect}
* @param mapper - the key mapping to be applied
* @param <K1> the type to map the keys into
* @return a new MapStream
*/
default <K1> MapStream<K1, V> mapKeys(Function<? super K, ? extends K1> mapper) {
return new DefaultMapStream<>(map(e -> new SimpleImmutableEntry<>(mapper.apply(e.getKey()), e.getValue())));
}
/**
* Applies the mapping for each values in the map.
* @param mapper - the value mapping to be applied
* @param <V1> the type to map the values into
* @return a new MapStream
*/
default <V1> MapStream<K, V1> mapValues(Function<? super V, ? extends V1> mapper) {
return new DefaultMapStream<>(map(e -> new SimpleImmutableEntry<>(e.getKey(), mapper.apply(e.getValue()))));
}
/**
* Applies the mapping for each keys and values in the map. If your mapping function is not
* bijective for the keys, make sure you call {@code mergeKeys} or that you provide a merge
* function when calling {@code collect}.
* @param keyMapper - the key mapping to be applied
* @param valueMapper - the value mapping to be applied
* @param <K1> the type to map the keys into
* @param <V1> the type to map the values into
* @return a new MapStream
*/
default <K1, V1> MapStream<K1, V1> mapEntries(Function<? super K, ? extends K1> keyMapper, Function<? super V, ? extends V1> valueMapper) {
return new DefaultMapStream<>(map(e -> new SimpleImmutableEntry<>(keyMapper.apply(e.getKey()), valueMapper.apply(e.getValue()))));
}
/**
* Applies the mapping for each (key, value) pair in the map.
* @param mapper the mapping function to be applied
* @param <R> the type to map the (key, value) pairs into
* @return a new Stream
*/
default <R> Stream<R> mapEntries(BiFunction<? super K, ? super V, ? extends R> mapper) {
return map(e -> mapper.apply(e.getKey(), e.getValue()));
}
/**
* Merge keys of the Stream into a new Stream
* @return a new MapStream
*/
default MapStream<K, List<V>> mergeKeys() {
return of(collect(groupingBy(Entry::getKey, mapping(Entry::getValue, toList()))));
}
/**
* Merge keys of the Stream into a new Stream with the merge function provided
* @param mergeFunction The merge function to use
* @return a new MapStream
*/
default MapStream<K, V> mergeKeys(BinaryOperator<V> mergeFunction) {
return of(collect(mergeFunction));
}
/**
* Return a Map from the stream. If you have similar keys in the stream,
* don't forget to call {@code mergeKeys()} or {@code collect (BinaryOperator<V> mergeFunction)}
* @return a map
*/
default Map<K, V> collect() {
return collect(toMap(Entry::getKey, Entry::getValue));
}
/**
* Return a Map from the stream. If there are similar keys in the stream,
* the merge function will be applied to merge the values of those keys
* @param mergeFunction the function to merge the values if the keys are not unique
* @return a map
*/
default Map<K, V> collect(BinaryOperator<V> mergeFunction) {
return collect(toMap(Entry::getKey, Entry::getValue, mergeFunction));
}
/**
* Return a MapStream from which the key and values are reversed.
* @return a new MapStream
*/
default MapStream<V, K> inverseMapping() {
return new DefaultMapStream<>(map(e -> new SimpleImmutableEntry<>(e.getValue(), e.getKey())));
}
@Override
MapStream<K, V> limit(long n);
@Override
MapStream<K, V> skip(long n);
@Override
MapStream<K, V> sorted();
@Override
MapStream<K, V> sorted(Comparator<? super Entry<K, V>> comparator);
@Override
MapStream<K, V> peek(Consumer<? super Entry<K, V>> action);
@Override
MapStream<K, V> onClose(Runnable closeHandler);
@Override
MapStream<K, V> filter(Predicate<? super Entry<K, V>> predicate);
@Override
MapStream<K, V> parallel();
@Override
MapStream<K, V> sequential();
@Override
MapStream<K, V> unordered();
@Override
MapStream<K, V> distinct();
}