All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.whaka.util.function.MapStream Maven / Gradle / Ivy

package org.whaka.util.function;

import static org.whaka.util.UberMaps.*;
import static org.whaka.util.UberPredicates.*;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;

import org.whaka.util.UberMaps;
import org.whaka.util.UberMaps.Entry;

public class MapStream implements Stream> {

	private final Stream> actual;
	
	public MapStream(Map map) {
		this(map.entrySet().stream());
	}
	
	public MapStream(Stream> actual) {
		this.actual = actual.map(UberMaps::entry);
	}

	private Stream> getActual() {
		return actual;
	}

	@Override
	public Iterator> iterator() {
		return getActual().iterator();
	}

	@Override
	public Spliterator> spliterator() {
		return getActual().spliterator();
	}

	@Override
	public boolean isParallel() {
		return getActual().isParallel();
	}

	@Override
	public MapStream sequential() {
		return new MapStream<>(getActual().sequential());
	}

	@Override
	public MapStream parallel() {
		return new MapStream<>(getActual().parallel());
	}

	@Override
	public MapStream unordered() {
		return new MapStream<>(getActual().unordered());
	}

	@Override
	public MapStream onClose(Runnable closeHandler) {
		return new MapStream<>(getActual().onClose(closeHandler));
	}

	@Override
	public void close() {
		getActual().close();
	}

	@Override
	public MapStream filter(Predicate> predicate) {
		return new MapStream<>(getActual().filter(predicate));
	}
	
	/**
	 * Each entry in the stream are matched as key/value pair against the specified predicate.
	 * Only the successfully matched entries are retained in the stream.
	 */
	public MapStream filter(BiPredicate predicate) {
		return filter(e -> predicate.test(e.key, e.val));
	}
	
	/**
	 * Filter out only the entries where key matches specified predicate.
	 */
	public MapStream filterKey(Predicate keyPredicate) {
		return filter(e -> keyPredicate.test(e.key));
	}
	
	/**
	 * Filter out only the entries where value matches specified predicate.
	 */
	public MapStream filterValue(Predicate valPredicate) {
		return filter(e -> valPredicate.test(e.val));
	}

	/**
	 * 

Filter only the keys that are instances of the specified class (or nulls) and cast them to the specified type. * *

Note: nulls survive the filtering! * Use separate filters to drop nulls! */ public MapStream filterKeyByClass(Class filteredKeyClass) { return filterKey(createIsNullOrInstancePredicate(filteredKeyClass)).mapKey(filteredKeyClass::cast); } /** *

Filter only the values that are instances of the specified class (or nulls) and cast them to the specified type. * *

Note: nulls survive the filtering! * Use separate filters to drop nulls! */ public MapStream filterValueByClass(Class filteredValueClass) { return filterValue(createIsNullOrInstancePredicate(filteredValueClass)).mapValue(filteredValueClass::cast); } private static Predicate createIsNullOrInstancePredicate(Class predicatedClass) { return anyOf(Objects::isNull, predicatedClass::isInstance); } /** * All the entries that do match specified predicate are removed from the stream. */ public MapStream drop(Predicate> predicate) { return filter(not(predicate)); } /** * Each entry in the stream are matched as key/value pair against the specified predicate. * All the successfully matched entries are removed from the stream. */ public MapStream drop(BiPredicate predicate) { return drop(e -> predicate.test(e.key, e.val)); } /** * All the entries where key matches specified predicate are removed from the stream. */ public MapStream dropKey(Predicate keyPredicate) { return filterKey(not(keyPredicate)); } /** * All the entries where value matches specified predicate are removed from the stream. */ public MapStream dropValue(Predicate valPredicate) { return filterValue(not(valPredicate)); } @Override public UberStream map(Function, ? extends R> mapper) { return new UberStream<>(getActual().map(mapper)); } /** * Each entry in the stream is mapped by the specified function into another entry. */ public MapStream mapEntry(Function, ? extends Map.Entry> mapper) { return new MapStream<>(getActual().map(mapper)); } /** * Each key/value pair in the stream is mapped by the specified BiFunction into another entry. */ public MapStream mapEntry(BiFunction> mapper) { return mapEntry(e -> mapper.apply(e.key, e.val)); } /** * For each entry in the stream - key is mapped by the specified key mapper function, and value is mapped * by the specified value mapper function. */ public MapStream mapEntry(Function keyMapper, Function valMapper) { return mapEntry((k,v) -> entry(keyMapper.apply(k), valMapper.apply(v))); } /** * For each entry in the stream - key is mapped by the specified key mapper function, value is untouched. */ public MapStream mapKey(Function keyMapper) { return mapEntry(keyMapper, Function.identity()); } /** * For each entry in the stream - key is untouched, and value is mapped by the specified value mapper function. */ public MapStream mapValue(Function valMapper) { return mapEntry(Function.identity(), valMapper); } @Override public IntStream mapToInt(ToIntFunction> mapper) { return getActual().mapToInt(mapper); } @Override public LongStream mapToLong(ToLongFunction> mapper) { return getActual().mapToLong(mapper); } @Override public DoubleStream mapToDouble(ToDoubleFunction> mapper) { return getActual().mapToDouble(mapper); } @Override public UberStream flatMap(Function, ? extends Stream> mapper) { return new UberStream<>(getActual().flatMap(mapper)); } /** * Each entry in the stream is mapped by the specified function into another map. Then each produced map * is flattened into a stream of entries, and they are combined into a single resulting stream. */ public MapStream flatMapEntry(Function, ? extends Map> mapper) { return new MapStream<>(getActual().flatMap(e -> mapper.apply(e).entrySet().stream())); } /** * For each entry in the stream - key is mapped by the specified function into a collection. * Then result stream is mapped into stream of map entries where keys are stream elements, and values are * the value of the original key. For example: *

	 * 	Map map = {1=10, 2=20};
	 * 	Map map2 = new MapStream(map).flatMapKey(i -> asList(i, i * 10)).collect();
	 * 	System.out.println(map2); // {1=10, 10=10, 2=20, 20=20}
	 * 
*/ public MapStream flatMapKey(Function> mapper) { return flatMapEntry(e -> new MapStream<>(mapper.apply(e.key).stream().map(k -> UberMaps.entry(k, e.val))).toMap()); } @Override public IntStream flatMapToInt(Function, ? extends IntStream> mapper) { return getActual().flatMapToInt(mapper); } @Override public LongStream flatMapToLong(Function, ? extends LongStream> mapper) { return getActual().flatMapToLong(mapper); } @Override public DoubleStream flatMapToDouble(Function, ? extends DoubleStream> mapper) { return getActual().flatMapToDouble(mapper); } @Override public MapStream distinct() { return new MapStream<>(getActual().distinct()); } /** * Only the entries with unique value are preserved in the stream. */ public MapStream distinctValues() { Set set = new HashSet<>(); return filterValue(set::add); } @Override public MapStream sorted() { return new MapStream<>(getActual().sorted()); } @Override public MapStream sorted(Comparator> comparator) { return new MapStream<>(getActual().sorted(comparator)); } /** * All entries in the stream are sorted by comparing keys using specified comparator. */ public MapStream sortedKeys(Comparator comparator) { return sorted(Map.Entry.comparingByKey(comparator)); } /** * All entries in the stream are sorted by comparing values using specified comparator. */ public MapStream sortedValues(Comparator comparator) { return sorted(Map.Entry.comparingByValue(comparator)); } @Override public MapStream peek(Consumer> action) { return new MapStream<>(getActual().peek(action)); } /** * Specified consumer are called for each key in the stream. */ public MapStream peekKeys(Consumer action) { return peek(e -> action.accept(e.key)); } /** * Specified consumer are called for each value in the stream. */ public MapStream peekValues(Consumer action) { return peek(e -> action.accept(e.val)); } @Override public MapStream limit(long maxSize) { return new MapStream<>(getActual().limit(maxSize)); } @Override public MapStream skip(long n) { return new MapStream<>(getActual().skip(n)); } @Override public void forEach(Consumer> action) { getActual().forEach(action); } /** * Each entry in the stream are passed as key/value pair into the specified consumer. */ public void forEach(BiConsumer action) { forEach(e -> action.accept(e.key, e.val)); } /** * Specified consumer are called for each key in the stream. */ public void forEachKey(Consumer action) { getActual().forEach(e -> action.accept(e.key)); } /** * Specified consumer are called for each value in the stream. */ public void forEachValue(Consumer action) { getActual().forEach(e -> action.accept(e.val)); } @Override public void forEachOrdered(Consumer> action) { getActual().forEachOrdered(action); } /** * Map all entries in the stream by {@link Entry#getKey()} method. */ public UberStream toKeys() { return map(Entry::getKey); } /** * Map all entries in the stream by {@link Entry#getValue()} method. */ public UberStream toValues() { return map(Entry::getValue); } @Override public Object[] toArray() { return getActual().toArray(); } @Override public A[] toArray(IntFunction generator) { return getActual().toArray(generator); } @Override public UberMaps.Entry reduce(UberMaps.Entry identity, BinaryOperator> accumulator) { return getActual().reduce(identity, accumulator); } @Override public Optional> reduce(BinaryOperator> accumulator) { return getActual().reduce(accumulator); } @Override public U reduce(U identity, BiFunction, U> accumulator, BinaryOperator combiner) { return getActual().reduce(identity, accumulator, combiner); } /** * Collect stream back to the map form. No additional parameters required, for map is built from the entries. * @see MapCollectors#toMap() */ public Map toMap() { return getActual().collect(MapCollectors.toMap()); } /** * Collect stream to the linked map. No additional parameters required, for map is built from the entries. * @see MapCollectors#toMap() */ public Map toLinkedMap() { return to(LinkedHashMap::new); } /** * Collect stream into a map provided by the specified supplier. * No additional parameters required, for map is built from the entries. * @see MapCollectors#toMap() */ public > M to(Supplier mapSupplier) { return getActual().collect(MapCollectors.toMap(mapSupplier)); } @Override public R collect(Supplier supplier, BiConsumer> accumulator, BiConsumer combiner) { return getActual().collect(supplier, accumulator, combiner); } @Override public R collect(Collector, A, R> collector) { return getActual().collect(collector); } @Override public Optional> min(Comparator> comparator) { return getActual().min(comparator); } @Override public Optional> max(Comparator> comparator) { return getActual().max(comparator); } @Override public long count() { return getActual().count(); } @Override public boolean anyMatch(Predicate> predicate) { return getActual().anyMatch(predicate); } @Override public boolean allMatch(Predicate> predicate) { return getActual().allMatch(predicate); } @Override public boolean noneMatch(Predicate> predicate) { return getActual().noneMatch(predicate); } @Override public Optional> findFirst() { return getActual().findFirst(); } @Override public Optional> findAny() { return getActual().findAny(); } /** * Find first entry that matches specified predicate. */ public Optional> find(Predicate> predicate) { return filter(predicate).findFirst(); } /** * Find first entry where key matches specified predicate. */ public Optional> findKey(Predicate keyPredicate) { return filterKey(keyPredicate).findFirst(); } /** * Find first entry where key is equal to the specified object. */ public Optional> findByKey(K key) { return findKey(Predicate.isEqual(key)); } }