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

javaslang.collection.TreeMap Maven / Gradle / Ivy

There is a newer version: 8.1.2
Show newest version
/*     / \____  _    _  ____   ______  / \ ____  __    _______
 *    /  /    \/ \  / \/    \ /  /\__\/  //    \/  \  //  /\__\   JΛVΛSLΛNG
 *  _/  /  /\  \  \/  /  /\  \\__\\  \  //  /\  \ /\\/ \ /__\ \   Copyright 2014-2016 Javaslang, http://javaslang.io
 * /___/\_/  \_/\____/\_/  \_/\__\/__/\__\_/  \_//  \__/\_____/   Licensed under the Apache License, Version 2.0
 */
package javaslang.collection;

import javaslang.Kind2;
import javaslang.Tuple;
import javaslang.Tuple2;
import javaslang.control.Option;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.*;
import java.util.stream.Collector;

import static javaslang.collection.Comparators.naturalComparator;

/**
 * SortedMap implementation, backed by a Red/Black Tree.
 *
 * @param  Key type
 * @param  Value type
 * @author Daniel Dietrich
 * @since 2.0.0
 */
// DEV-NOTE: use entries.min().get() in favor of iterator().next(), it is faster!
public final class TreeMap implements Kind2, K, V>, SortedMap, Serializable {

    private static final long serialVersionUID = 1L;

    private final RedBlackTree> entries;

    private TreeMap(RedBlackTree> entries) {
        this.entries = entries;
    }

    /**
     * Returns a {@link java.util.stream.Collector} which may be used in conjunction with
     * {@link java.util.stream.Stream#collect(java.util.stream.Collector)} to obtain a
     * {@link javaslang.collection.TreeMap}.
     *
     * @param  The key type
     * @param  The value type
     * @return A {@link TreeMap} Collector.
     */
    public static  Collector, ArrayList>, TreeMap> collector() {
        final Supplier>> supplier = ArrayList::new;
        final BiConsumer>, Tuple2> accumulator = ArrayList::add;
        final BinaryOperator>> combiner = (left, right) -> {
            left.addAll(right);
            return left;
        };
        final Comparator comparator = naturalComparator();
        final Function>, TreeMap> finisher = list -> TreeMap.ofEntries(comparator, list);
        return Collector.of(supplier, accumulator, combiner, finisher);
    }

    /**
     * Returns the empty TreeMap. The underlying key comparator is the natural comparator of K.
     *
     * @param  The key type
     * @param  The value type
     * @return A new empty TreeMap.
     */
    public static , V> TreeMap empty() {
        return empty((Comparator & Serializable) K::compareTo);
    }

    /**
     * Returns the empty TreeMap using the given key comparator.
     *
     * @param            The key type
     * @param            The value type
     * @param keyComparator The comparator used to sort the entries by their key.
     * @return A new empty TreeMap.
     */
    public static  TreeMap empty(Comparator keyComparator) {
        Objects.requireNonNull(keyComparator, "keyComparator is null");
        return new TreeMap<>(RedBlackTree.empty(new EntryComparator<>(keyComparator)));
    }

    /**
     * Narrows a widened {@code TreeMap} to {@code TreeMap}
     * by performing a type safe-cast. This is eligible because immutable/read-only
     * collections are covariant.
     * 

* CAUTION: If {@code K} is narrowed, the underlying {@code Comparator} might fail! * * @param treeMap A {@code TreeMap}. * @param Key type * @param Value type * @return the given {@code treeMap} instance as narrowed type {@code TreeMap}. */ @SuppressWarnings("unchecked") public static TreeMap narrow(TreeMap treeMap) { return (TreeMap) treeMap; } /** * Returns a singleton {@code TreeMap}, i.e. a {@code TreeMap} of one entry. * The underlying key comparator is the natural comparator of K. * * @param The key type * @param The value type * @param entry A map entry. * @return A new TreeMap containing the given entry. */ public static , V> TreeMap of(Tuple2 entry) { return of((Comparator & Serializable) K::compareTo, entry); } /** * Creates a TreeMap of the given list of key-value pairs. * * @param pairs A list of key-value pairs * @param The key type * @param The value type * @return A new Map containing the given entries */ @SuppressWarnings("unchecked") public static TreeMap of(Object... pairs) { Objects.requireNonNull(pairs, "pairs is null"); if ((pairs.length & 1) != 0) { throw new IllegalArgumentException("Odd length of key-value pairs list"); } RedBlackTree> result = RedBlackTree.empty(); for (int i = 0; i < pairs.length; i += 2) { result = result.insert(Tuple.of((K) pairs[i], (V) pairs[i + 1])); } return new TreeMap<>(result); } /** * Returns a {@code TreeMap}, from a source java.util.Map. * * @param map A map entry. * @param The key type * @param The value type * @return A new Map containing the given map */ public static , V> TreeMap ofAll(java.util.Map map) { Objects.requireNonNull(map, "map is null"); RedBlackTree> result = RedBlackTree.empty(new EntryComparator<>((Comparator & Serializable) K::compareTo)); for (java.util.Map.Entry entry : map.entrySet()) { result = result.insert(Tuple.of(entry.getKey(), entry.getValue())); } return new TreeMap<>(result); } /** * Returns a singleton {@code TreeMap}, i.e. a {@code TreeMap} of one entry using a specific key comparator. * * @param The key type * @param The value type * @param entry A map entry. * @param keyComparator The comparator used to sort the entries by their key. * @return A new TreeMap containing the given entry. */ public static TreeMap of(Comparator keyComparator, Tuple2 entry) { Objects.requireNonNull(keyComparator, "keyComparator is null"); Objects.requireNonNull(entry, "entry is null"); return TreeMap. empty(keyComparator).put(entry); } /** * Returns a singleton {@code TreeMap}, i.e. a {@code TreeMap} of one element. * * @param key A singleton map key. * @param value A singleton map value. * @param The key type * @param The value type * @return A new Map containing the given entry */ public static , V> TreeMap of(K key, V value) { return of((Comparator & Serializable) K::compareTo, key, value); } /** * Returns a singleton {@code TreeMap}, i.e. a {@code TreeMap} of one element. * * @param key A singleton map key. * @param value A singleton map value. * @param The key type * @param The value type * @param keyComparator The comparator used to sort the entries by their key. * @return A new Map containing the given entry */ public static , V> TreeMap of(Comparator keyComparator, K key, V value) { Objects.requireNonNull(keyComparator, "keyComparator is null"); return TreeMap. empty(keyComparator).put(key, value); } /** * Returns a TreeMap containing {@code n} values of a given Function {@code f} * over a range of integer values from 0 to {@code n - 1}. * * @param The key type * @param The value type * @param keyComparator The comparator used to sort the entries by their key * @param n The number of elements in the TreeMap * @param f The Function computing element values * @return A TreeMap consisting of elements {@code f(0),f(1), ..., f(n - 1)} * @throws NullPointerException if {@code keyComparator} or {@code f} are null */ @SuppressWarnings("unchecked") public static TreeMap tabulate(Comparator keyComparator, int n, Function> f) { Objects.requireNonNull(keyComparator, "keyComparator is null"); Objects.requireNonNull(f, "f is null"); return ofEntries(keyComparator, Collections.tabulate(n, (Function>) f)); } /** * Returns a TreeMap containing {@code n} values of a given Function {@code f} * over a range of integer values from 0 to {@code n - 1}. * The underlying key comparator is the natural comparator of K. * * @param The key type * @param The value type * @param n The number of elements in the TreeMap * @param f The Function computing element values * @return A TreeMap consisting of elements {@code f(0),f(1), ..., f(n - 1)} * @throws NullPointerException if {@code f} is null */ public static , V> TreeMap tabulate(int n, Function> f) { Objects.requireNonNull(f, "f is null"); return tabulate((Comparator & Serializable) K::compareTo, n, f); } /** * Returns a TreeMap containing {@code n} values supplied by a given Supplier {@code s}. * * @param The key type * @param The value type * @param keyComparator The comparator used to sort the entries by their key * @param n The number of elements in the TreeMap * @param s The Supplier computing element values * @return A TreeMap of size {@code n}, where each element contains the result supplied by {@code s}. * @throws NullPointerException if {@code keyComparator} or {@code s} are null */ @SuppressWarnings("unchecked") public static TreeMap fill(Comparator keyComparator, int n, Supplier> s) { Objects.requireNonNull(keyComparator, "keyComparator is null"); Objects.requireNonNull(s, "s is null"); return ofEntries(keyComparator, Collections.fill(n, (Supplier>) s)); } /** * Returns a TreeMap containing {@code n} values supplied by a given Supplier {@code s}. * The underlying key comparator is the natural comparator of K. * * @param The key type * @param The value type * @param n The number of elements in the TreeMap * @param s The Supplier computing element values * @return A TreeMap of size {@code n}, where each element contains the result supplied by {@code s}. * @throws NullPointerException if {@code s} is null */ public static , V> TreeMap fill(int n, Supplier> s) { Objects.requireNonNull(s, "s is null"); return fill((Comparator & Serializable) K::compareTo, n, s); } /** * Creates a {@code TreeMap} of the given entries using the natural key comparator. * * @param The key type * @param The value type * @param entries Map entries * @return A new TreeMap containing the given entries. */ @SuppressWarnings("varargs") @SafeVarargs public static , V> TreeMap ofEntries(Tuple2... entries) { return ofEntries((Comparator & Serializable) K::compareTo, entries); } /** * Creates a {@code TreeMap} of the given entries using the natural key comparator. * * @param The key type * @param The value type * @param entries Map entries * @return A new TreeMap containing the given entries. */ @SuppressWarnings("varargs") @SafeVarargs public static , V> TreeMap ofEntries(java.util.Map.Entry... entries) { return ofEntries((Comparator & Serializable) K::compareTo, entries); } /** * Creates a {@code TreeMap} of the given entries using the given key comparator. * * @param The key type * @param The value type * @param entries Map entries * @param keyComparator A key comparator * @return A new TreeMap containing the given entries. */ @SuppressWarnings("unchecked") @SafeVarargs public static TreeMap ofEntries(Comparator keyComparator, Tuple2... entries) { Objects.requireNonNull(keyComparator, "keyComparator is null"); Objects.requireNonNull(entries, "entries is null"); RedBlackTree> tree = RedBlackTree.empty(new EntryComparator<>(keyComparator)); for (Tuple2 entry : entries) { tree = tree.insert((Tuple2) entry); } return tree.isEmpty() ? empty(keyComparator) : new TreeMap<>(tree); } /** * Creates a {@code TreeMap} of the given entries using the given key comparator. * * @param The key type * @param The value type * @param entries Map entries * @param keyComparator A key comparator * @return A new TreeMap containing the given entries. */ @SafeVarargs public static TreeMap ofEntries(Comparator keyComparator, java.util.Map.Entry... entries) { Objects.requireNonNull(keyComparator, "keyComparator is null"); Objects.requireNonNull(entries, "entries is null"); RedBlackTree> tree = RedBlackTree.empty(new EntryComparator<>(keyComparator)); for (java.util.Map.Entry entry : entries) { tree = tree.insert(Tuple.of(entry.getKey(), entry.getValue())); } return tree.isEmpty() ? empty(keyComparator) : new TreeMap<>(tree); } /** * Creates a {@code TreeMap} of the given entries. * * @param The key type * @param The value type * @param entries Map entries * @return A new TreeMap containing the given entries. */ public static , V> TreeMap ofEntries(Iterable> entries) { return ofEntries((Comparator & Serializable) K::compareTo, entries); } /** * Creates a {@code TreeMap} of the given entries. * * @param The key type * @param The value type * @param entries Map entries * @param keyComparator A key comparator * @return A new TreeMap containing the given entries. */ @SuppressWarnings("unchecked") public static TreeMap ofEntries(Comparator keyComparator, Iterable> entries) { Objects.requireNonNull(keyComparator, "keyComparator is null"); Objects.requireNonNull(entries, "entries is null"); if (entries instanceof TreeMap) { return (TreeMap) entries; } else { RedBlackTree> tree = RedBlackTree.empty(new EntryComparator<>(keyComparator)); for (Tuple2 entry : entries) { tree = tree.insert((Tuple2) entry); } return new TreeMap<>(tree); } } @Override public TreeMap bimap(Function keyMapper, Function valueMapper) { return bimap(naturalComparator(), keyMapper, valueMapper); } @Override public TreeMap bimap(Comparator keyComparator, Function keyMapper, Function valueMapper) { Objects.requireNonNull(keyMapper, "keyMapper is null"); Objects.requireNonNull(valueMapper, "valueMapper is null"); return createTreeMap(new EntryComparator<>(keyComparator), entries.iterator().map(entry -> Tuple.of(keyMapper.apply(entry._1), valueMapper.apply(entry._2)))); } @Override public boolean containsKey(K key) { final V ignored = null; return entries.contains(new Tuple2<>(key, ignored)); } @Override public TreeMap distinct() { return Maps.distinct(this); } @Override public TreeMap distinctBy(Comparator> comparator) { return Maps.distinctBy(this, this::createFromEntries, comparator); } @Override public TreeMap distinctBy(Function, ? extends U> keyExtractor) { return Maps.distinctBy(this, this::createFromEntries, keyExtractor); } @Override public TreeMap drop(long n) { return Maps.drop(this, this::createFromEntries, this::emptyInstance, n); } @Override public TreeMap dropRight(long n) { return Maps.dropRight(this, this::createFromEntries, this::emptyInstance, n); } @Override public TreeMap dropUntil(Predicate> predicate) { return Maps.dropUntil(this, this::createFromEntries, predicate); } @Override public TreeMap dropWhile(Predicate> predicate) { return Maps.dropWhile(this, this::createFromEntries, predicate); } @Override public TreeMap filter(Predicate> predicate) { return Maps.filter(this, this::createFromEntries, predicate); } @Override public TreeMap flatMap(BiFunction>> mapper) { return flatMap(naturalComparator(), mapper); } @Override public TreeMap flatMap(Comparator keyComparator, BiFunction>> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return createTreeMap(new EntryComparator<>(keyComparator), entries.iterator().flatMap(entry -> mapper.apply(entry._1, entry._2))); } @Override public Option get(K key) { final V ignored = null; return entries.find(new Tuple2<>(key, ignored)).map(Tuple2::_2); } @Override public Map> groupBy(Function, ? extends C> classifier) { return Maps.groupBy(this, this::createFromEntries, classifier); } @Override public Iterator> grouped(long size) { return Maps.grouped(this, this::createFromEntries, size); } @Override public Tuple2 head() { if (isEmpty()) { throw new NoSuchElementException("head of empty TreeMap"); } else { return entries.min().get(); } } @Override public TreeMap init() { if (isEmpty()) { throw new UnsupportedOperationException("init of empty TreeMap"); } else { final Tuple2 max = entries.max().get(); return new TreeMap<>(entries.delete(max)); } } @Override public Option> initOption() { return Maps.initOption(this); } @Override public boolean isEmpty() { return entries.isEmpty(); } @Override public Iterator> iterator() { return entries.iterator(); } @SuppressWarnings("unchecked") @Override public Comparator keyComparator() { return ((EntryComparator) entries.comparator()).keyComparator; } @Override public SortedSet keySet() { return TreeSet.ofAll(keyComparator(), iterator().map(Tuple2::_1)); } @Override public TreeMap map(BiFunction> mapper) { return map(naturalComparator(), mapper); } @Override public TreeMap map(Comparator keyComparator, BiFunction> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return createTreeMap(new EntryComparator<>(keyComparator), entries.iterator().map(entry -> mapper.apply(entry._1, entry._2))); } @Override public TreeMap mapValues(Function valueMapper) { Objects.requireNonNull(valueMapper, "valueMapper is null"); return map(keyComparator(), (k, v) -> Tuple.of(k, valueMapper.apply(v))); } @Override public TreeMap merge(Map that) { return Maps.merge(this, this::createFromEntries, that); } @Override public TreeMap merge(Map that, BiFunction collisionResolution) { return Maps.merge(this, this::createFromEntries, that, collisionResolution); } @Override public Tuple2, TreeMap> partition(Predicate> predicate) { return Maps.partition(this, this::createFromEntries, predicate); } @Override public TreeMap peek(Consumer> action) { return Maps.peek(this, action); } @Override public TreeMap put(K key, V value) { return new TreeMap<>(entries.insert(new Tuple2<>(key, value))); } @Override public TreeMap put(Tuple2 entry) { return Maps.put(this, entry); } @Override public TreeMap remove(K key) { final V ignored = null; final Tuple2 entry = new Tuple2<>(key, ignored); if (entries.contains(entry)) { return new TreeMap<>(entries.delete(entry)); } else { return this; } } @Override public TreeMap removeAll(Iterable keys) { final V ignored = null; RedBlackTree> removed = entries; for (K key : keys) { final Tuple2 entry = new Tuple2<>(key, ignored); if (removed.contains(entry)) { removed = removed.delete(entry); } } if (removed.size() == entries.size()) { return this; } else { return new TreeMap<>(removed); } } @Override public TreeMap replace(Tuple2 currentElement, Tuple2 newElement) { return Maps.replace(this, currentElement, newElement); } @Override public TreeMap replaceAll(Tuple2 currentElement, Tuple2 newElement) { return Maps.replaceAll(this, currentElement, newElement); } @Override public TreeMap retainAll(Iterable> elements) { Objects.requireNonNull(elements, "elements is null"); RedBlackTree> tree = RedBlackTree.empty(entries.comparator()); for (Tuple2 entry : elements) { if (contains(entry)) { tree = tree.insert(entry); } } return new TreeMap<>(tree); } @Override public TreeMap scan( Tuple2 zero, BiFunction, ? super Tuple2, ? extends Tuple2> operation) { return Maps.scan(this, this::emptyInstance, zero, operation); } @Override public int size() { return entries.size(); } @Override public Iterator> sliding(long size) { return Maps.sliding(this, this::createFromEntries, size); } @Override public Iterator> sliding(long size, long step) { return Maps.sliding(this, this::createFromEntries, size, step); } @Override public Tuple2, TreeMap> span(Predicate> predicate) { return Maps.span(this, this::createFromEntries, predicate); } @Override public TreeMap tail() { if (isEmpty()) { throw new UnsupportedOperationException("tail of empty TreeMap"); } else { final Tuple2 min = entries.min().get(); return new TreeMap<>(entries.delete(min)); } } @Override public Option> tailOption() { return Maps.tailOption(this); } @Override public TreeMap take(long n) { return Maps.take(this, this::createFromEntries, n); } @Override public TreeMap takeRight(long n) { return Maps.takeRight(this, this::createFromEntries, n); } @Override public TreeMap takeUntil(Predicate> predicate) { return Maps.takeUntil(this, this::createFromEntries, predicate); } @Override public TreeMap takeWhile(Predicate> predicate) { return Maps.takeWhile(this, this::createFromEntries, predicate); } @Override public java.util.TreeMap toJavaMap() { return toJavaMap(() -> new java.util.TreeMap<>(keyComparator()), t -> t); } @Override public Seq values() { return iterator().map(Tuple2::_2).toStream(); } /** * Internal factory method, used with Tuple2 comparator instead of a key comparator. * * @param comparator An Tuple2 comparator * @param entries Map entries * @param Key type * @param Value type * @return A new TreeMap. */ @SuppressWarnings("unchecked") private static TreeMap createTreeMap(Comparator> comparator, Iterable> entries) { RedBlackTree> tree = RedBlackTree.empty(comparator); for (Tuple2 entry : entries) { tree = tree.insert((Tuple2) entry); } return tree.isEmpty() ? (TreeMap) empty() : new TreeMap<>(tree); } // -- Object @Override public boolean equals(Object o) { if (o == this) { return true; } else if (o instanceof TreeMap) { final TreeMap that = (TreeMap) o; return entries.equals(that.entries); } else { return false; } } @Override public int hashCode() { return entries.hashCode(); } @Override public String stringPrefix() { return "TreeMap"; } @Override public String toString() { return mkString(stringPrefix() + "(", ", ", ")"); } private TreeMap createFromEntries(Iterable> tuples) { return createTreeMap(entries.comparator(), tuples); } private TreeMap emptyInstance() { return isEmpty() ? this : new TreeMap<>(entries.emptyInstance()); } /** * Used to compare entries by key and store the keyComparator for later access. * * @param key type * @param value type, needed at compile time for the Comparator interface */ static class EntryComparator implements Comparator>, Serializable { private static final long serialVersionUID = 1L; final Comparator keyComparator; @SuppressWarnings("unchecked") EntryComparator(Comparator keyComparator) { this.keyComparator = (Comparator) keyComparator; } @Override public int compare(Tuple2 e1, Tuple2 e2) { return keyComparator.compare(e1._1, e2._1); } } }