![JAR search and dependency download from the Maven repository](/logo.png)
com.github.protobufel.multikeymap.Collectors Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of multikeymapjava Show documentation
Show all versions of multikeymapjava Show documentation
Java 8 implementation of the multi-key map. It behaves like a regular generic Map with the additional ability of getting its values by any combination of partial keys.
The newest version!
/*
* Copyright 2017 David Tesler
*
* 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.github.protobufel.multikeymap;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentHashMap.KeySetView;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import static java.util.Comparator.comparingInt;
/**
* The utility class providing the MultiKeyMap and multiple sets' intersection related collectors.
*
* @author David Tesler
*/
public final class Collectors {
private Collectors() {
}
/**
* Returns the Optional result of the intersection of all sets in the supplied Iterable.
*
* @param the type of the elements of the sets
* @param source the Iterable of the sets to intersect with each other
* @param parallel use parallel processing if true, sequential if false
* @return the result of the intersection wrapped in Optional, or the empty Optional.
*/
public static Set intersectSets(final Iterable extends Set> source,
final boolean parallel) {
return streamOf(Objects.requireNonNull(source), parallel)
.min(comparingInt(set -> Objects.requireNonNull(set).size()))
.map(smallestSet -> streamOf(source, parallel).collect(setIntersecting(smallestSet, parallel)))
.orElse(Collections.emptySet());
}
static Stream streamOf(final Iterable source, final boolean parallel) {
if (source instanceof Collection) {
final Collection collection = (Collection) source;
return (parallel ? collection.parallelStream() : collection.stream()).unordered();
} else {
return StreamSupport.stream(Objects.requireNonNull(source).spliterator(), parallel)
.unordered();
}
}
/**
* Gets a collector which intersects the stream of sets and returns the resulting set.
*
* @param smallestSet the smallest in size element of the stream of sets, any if there are several
* of the same size
* @param parallel use parallel processing if true, sequential if false
* @param the type of the elements of the sets
* @return the collector to perform the intersection of all elements of the stream of sets
*/
public static Collector, Set, Set> setIntersecting(final Set smallestSet,
final boolean parallel) {
return setIntersecting(() -> smallestSet, parallel);
}
/**
* Gets a collector which intersects the stream of sets and returns the resulting set.
*
* @param smallestSetSupplier the supplier of the smallest in size element of the stream of sets,
* any if there are several of the same size
* @param parallel use parallel processing if true, sequential if false
* @param the type of the elements of the sets
* @return the collector to perform the intersection of all elements of the stream of sets
*/
public static Collector, Set, Set> setIntersecting(
final Supplier> smallestSetSupplier, final boolean parallel) {
return parallel ? new ConcurrentSetIntersecting<>(smallestSetSupplier)
: new SequentialSetIntersecting<>(smallestSetSupplier);
}
/**
* Gets a MultiKeyMap producing collector.
*
* @param keyMapper the key producing mapping function
* @param valueMapper the value producing mapping function
* @param the type of the stream elements
* @param the type of the sub-keys of the MultiKeyMap
* @param the type of the keys of the MultiKeyMap
* @param the type of the values of the MultiKeyMap
* @return the MultiKeyMap producing collector
*/
public static , V> Collector> toMultiKeyMap(
final Function super T, ? extends K> keyMapper,
final Function super T, ? extends V> valueMapper) {
return java.util.stream.Collectors.toMap(keyMapper, valueMapper, (k, v) -> {
throw new IllegalStateException(String.format("duplicate key %s", k));
}, MultiKeyMaps::newMultiKeyMap);
}
/**
* Gets a MultiKeyMap producing collector.
*
* @param keyMapper the key producing mapping function
* @param valueMapper the value producing mapping function
* @param mergeFunction the value merging function
* @param the type of the stream elements
* @param the type of the sub-keys of the MultiKeyMap
* @param the type of the keys of the MultiKeyMap
* @param the type of the values of the MultiKeyMap
* @return the MultiKeyMap producing collector
*/
public static , V> Collector> toMultiKeyMap(
final Function super T, ? extends K> keyMapper,
final Function super T, ? extends V> valueMapper, final BinaryOperator mergeFunction) {
return java.util.stream.Collectors.toMap(keyMapper, valueMapper, mergeFunction,
MultiKeyMaps::newMultiKeyMap);
}
/**
* Gets a MultiKeyMap producing collector.
*
* @param keyMapper the key producing mapping function
* @param valueMapper the value producing mapping function
* @param mergeFunction the value merging function
* @param multiKeyMapSupplier the MultiKeyMap supplier
* @param the type of the stream elements
* @param the type of the sub-keys of the MultiKeyMap
* @param the type of the keys of the MultiKeyMap
* @param the type of the values of the MultiKeyMap
* @return the MultiKeyMap producing collector
*/
public static , V, M extends MultiKeyMap> Collector toMultiKeyMap(
final Function super T, ? extends K> keyMapper,
final Function super T, ? extends V> valueMapper, final BinaryOperator mergeFunction,
final Supplier multiKeyMapSupplier) {
return java.util.stream.Collectors.toMap(keyMapper, valueMapper, mergeFunction,
multiKeyMapSupplier);
}
static final class ConcurrentSetIntersecting implements Collector, Set, Set> {
private final Supplier> smallestSetSupplier;
ConcurrentSetIntersecting(final Supplier> smallestSetSupplier) {
super();
this.smallestSetSupplier = Objects.requireNonNull(smallestSetSupplier);
}
@Override
public Supplier> supplier() {
return () -> {
final Set smallestSet = smallestSetSupplier.get();
final KeySetView newKeySet = ConcurrentHashMap.newKeySet(smallestSet.size());
newKeySet.addAll(smallestSet);
return newKeySet;
};
}
@Override
public BiConsumer, Set> accumulator() {
return (set1, set2) -> {
if ((set2 != smallestSetSupplier.get()) && !set1.isEmpty() && !set2.isEmpty()) {
set1.retainAll(set2);
}
};
}
@Override
public BinaryOperator> combiner() {
return (set1, set2) -> set1.isEmpty() || set2.isEmpty()
|| (set1.retainAll(set2) && set1.isEmpty()) ? Collections.emptySet() : set1;
}
@Override
public Set characteristics() {
return Collections.unmodifiableSet(EnumSet.allOf(Characteristics.class));
}
@Override
public Function, Set> finisher() {
return Function.identity();
}
}
static final class SequentialSetIntersecting implements Collector, Set, Set> {
private final Supplier> smallestSetSupplier;
SequentialSetIntersecting(final Supplier> smallestSetSupplier) {
super();
this.smallestSetSupplier = Objects.requireNonNull(smallestSetSupplier);
}
@Override
public Supplier> supplier() {
return () -> new HashSet<>(smallestSetSupplier.get());
}
@Override
public BiConsumer, Set> accumulator() {
return (set1, set2) -> {
if ((set2 != smallestSetSupplier.get()) && !set1.isEmpty() && !set2.isEmpty()) {
set1.retainAll(set2);
}
};
}
@Override
public BinaryOperator> combiner() {
return (set1, set2) -> set1.isEmpty() || set2.isEmpty()
|| (set1.retainAll(set2) && set1.isEmpty()) ? Collections.emptySet() : set1;
}
@Override
public Set characteristics() {
return Collections
.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH, Characteristics.UNORDERED));
}
@Override
public Function, Set> finisher() {
return Function.identity();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy