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: 2.1.0-alpha
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}.
     * 

* The natural comparator is used to compare TreeMap keys. * * @param The key type * @param The value type * @return A {@link TreeMap} Collector. */ public static , V> Collector, ArrayList>, TreeMap> collector() { return createCollector(EntryComparator.natural()); } /** * 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 * @param keyComparator The comparator used to sort the entries by their key. * @return A {@link TreeMap} Collector. */ public static Collector, ArrayList>, TreeMap> collector(Comparator keyComparator) { return createCollector(EntryComparator.of(keyComparator)); } /** * 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 new TreeMap<>(RedBlackTree.empty(EntryComparator.natural())); } /** * 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) { return new TreeMap<>(RedBlackTree.empty(EntryComparator.of(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) { Objects.requireNonNull(entry, "entry is null"); return createFromTuple(EntryComparator.natural(), entry); } /** * 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 keyComparator The comparator used to sort the entries by their key. * @param entry A map entry. * @return A new TreeMap containing the given entry. */ public static TreeMap of(Comparator keyComparator, Tuple2 entry) { Objects.requireNonNull(entry, "entry is null"); return createFromTuple(EntryComparator.of(keyComparator), 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(EntryComparator.of(naturalComparator())); 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"); return createFromMap(EntryComparator.natural(), map); } /** * 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 createFromPairs(EntryComparator.natural(), key, value); } /** * Returns a singleton {@code TreeMap}, i.e. a {@code TreeMap} of one element. * * @param keyComparator The comparator used to sort the entries by their key. * @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 TreeMap of(Comparator keyComparator, K key, V value) { return createFromPairs(EntryComparator.of(keyComparator), 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 */ public static TreeMap tabulate(Comparator keyComparator, int n, Function> f) { Objects.requireNonNull(f, "f is null"); return createTreeMap(EntryComparator.of(keyComparator), Collections.tabulate(n, 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 createTreeMap(EntryComparator.natural(), Collections.tabulate(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(s, "s is null"); return createTreeMap(EntryComparator.of(keyComparator), Collections.fill(n, 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 createTreeMap(EntryComparator.natural(), Collections.fill(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 createFromTuples(EntryComparator.natural(), entries); } /** * Creates a {@code TreeMap} of the given entries 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. * @param entries Map entries * @return A new TreeMap containing the given entries. */ @SuppressWarnings({ "unchecked", "varargs" }) @SafeVarargs public static TreeMap ofEntries(Comparator keyComparator, Tuple2... entries) { return createFromTuples(EntryComparator.of(keyComparator), 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 createFromMapEntries(EntryComparator.natural(), entries); } /** * Creates a {@code TreeMap} of the given entries 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. * @param entries Map entries * @return A new TreeMap containing the given entries. */ @SuppressWarnings("varargs") @SafeVarargs public static TreeMap ofEntries(Comparator keyComparator, java.util.Map.Entry... entries) { return createFromMapEntries(EntryComparator.of(keyComparator), entries); } /** * 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 createTreeMap(EntryComparator.natural(), entries); } /** * Creates a {@code TreeMap} of the given entries. * * @param The key type * @param The value type * @param keyComparator The comparator used to sort the entries by their key. * @param entries Map entries * @return A new TreeMap containing the given entries. */ @SuppressWarnings("unchecked") public static TreeMap ofEntries(Comparator keyComparator, Iterable> entries) { return createTreeMap(EntryComparator.of(keyComparator), entries); } // -- TreeMap API @Override public TreeMap bimap(Function keyMapper, Function valueMapper) { return bimap(this, EntryComparator.natural(), keyMapper, valueMapper); } @Override public TreeMap bimap(Comparator keyComparator, Function keyMapper, Function valueMapper) { return bimap(this, EntryComparator.of(keyComparator), keyMapper, valueMapper); } @Override public boolean containsKey(K key) { return entries.contains(new Tuple2<>(key, /*ignored*/null)); } @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(this, EntryComparator.natural(), mapper); } @Override public TreeMap flatMap(Comparator keyComparator, BiFunction>> mapper) { return flatMap(this, EntryComparator.of(keyComparator), mapper); } @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(this, EntryComparator.natural(), mapper); } @Override public TreeMap map(Comparator keyComparator, BiFunction> mapper) { Objects.requireNonNull(keyComparator, "keyComparator is null"); return map(this, EntryComparator.of(keyComparator), mapper); } @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(); } // -- 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 helpers private static TreeMap bimap(TreeMap map, EntryComparator entryComparator, Function keyMapper, Function valueMapper) { Objects.requireNonNull(keyMapper, "keyMapper is null"); Objects.requireNonNull(valueMapper, "valueMapper is null"); return createTreeMap(entryComparator, map.entries, entry -> entry.map(keyMapper, valueMapper)); } private static TreeMap flatMap(TreeMap map, EntryComparator entryComparator, BiFunction>> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return createTreeMap(entryComparator, map.entries.iterator().flatMap(entry -> mapper.apply(entry._1, entry._2))); } private static TreeMap map(TreeMap map, EntryComparator entryComparator, BiFunction> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return createTreeMap(entryComparator, map.entries, entry -> entry.map(mapper)); } // -- internal factory methods private static Collector, ArrayList>, TreeMap> createCollector(EntryComparator entryComparator) { final Supplier>> supplier = ArrayList::new; final BiConsumer>, Tuple2> accumulator = ArrayList::add; final BinaryOperator>> combiner = (left, right) -> { left.addAll(right); return left; }; final Function>, TreeMap> finisher = list -> createTreeMap(entryComparator, list); return Collector.of(supplier, accumulator, combiner, finisher); } @SuppressWarnings("unchecked") private static TreeMap createTreeMap(EntryComparator entryComparator, Iterable> entries) { Objects.requireNonNull(entries, "entries is null"); RedBlackTree> tree = RedBlackTree.empty(entryComparator); for (Tuple2 entry : (Iterable>) entries) { tree = tree.insert(entry); } return new TreeMap<>(tree); } private static TreeMap createTreeMap(EntryComparator entryComparator, Iterable> entries, Function, Tuple2> entryMapper) { RedBlackTree> tree = RedBlackTree.empty(entryComparator); for (Tuple2 entry : entries) { tree = tree.insert(entryMapper.apply(entry)); } return new TreeMap<>(tree); } @SuppressWarnings("unchecked") private static TreeMap createFromMap(EntryComparator entryComparator, java.util.Map map) { Objects.requireNonNull(map, "map is null"); RedBlackTree> tree = RedBlackTree.empty(entryComparator); for (java.util.Map.Entry entry : ((java.util.Map) map).entrySet()) { tree = tree.insert(Tuple.of(entry.getKey(), entry.getValue())); } return new TreeMap<>(tree); } @SuppressWarnings("unchecked") private static TreeMap createFromTuple(EntryComparator entryComparator, Tuple2 entry) { Objects.requireNonNull(entry, "entry is null"); return new TreeMap<>(RedBlackTree.of(entryComparator, (Tuple2) entry)); } @SuppressWarnings("unchecked") private static TreeMap createFromTuples(EntryComparator entryComparator, Tuple2... entries) { Objects.requireNonNull(entries, "entries is null"); RedBlackTree> tree = RedBlackTree.empty(entryComparator); for (Tuple2 entry : entries) { tree = tree.insert((Tuple2) entry); } return new TreeMap<>(tree); } @SafeVarargs private static TreeMap createFromMapEntries(EntryComparator entryComparator, java.util.Map.Entry... entries) { Objects.requireNonNull(entries, "entries is null"); RedBlackTree> tree = RedBlackTree.empty(entryComparator); for (java.util.Map.Entry entry : entries) { final K key = entry.getKey(); final V value = entry.getValue(); tree = tree.insert(Tuple.of(key, value)); } return new TreeMap<>(tree); } @SuppressWarnings("unchecked") private static TreeMap createFromPairs(EntryComparator entryComparator, Object... pairs) { RedBlackTree> tree = RedBlackTree.empty(entryComparator); for (int i = 0; i < pairs.length; i += 2) { final K key = (K) pairs[i]; final V value = (V) pairs[i + 1]; tree = tree.insert(Tuple.of(key, value)); } return new TreeMap<>(tree); } private TreeMap createFromEntries(Iterable> tuples) { return createTreeMap((EntryComparator) entries.comparator(), tuples); } private TreeMap emptyInstance() { return isEmpty() ? this : new TreeMap<>(entries.emptyInstance()); } // -- internal types private interface EntryComparator extends Comparator>, Serializable { long serialVersionUID = 1L; static EntryComparator of(Comparator keyComparator) { Objects.requireNonNull(keyComparator, "keyComparator is null"); return new Specific<>(keyComparator); } static EntryComparator natural() { return Natural.instance(); } Comparator keyComparator(); // -- internal impls final class Specific implements EntryComparator { private static final long serialVersionUID = 1L; private final Comparator keyComparator; @SuppressWarnings("unchecked") Specific(Comparator keyComparator) { this.keyComparator = (Comparator) keyComparator; } @Override public int compare(Tuple2 e1, Tuple2 e2) { return keyComparator.compare(e1._1, e2._1); } @Override public Comparator keyComparator() { return keyComparator; } } final class Natural implements EntryComparator { private static final long serialVersionUID = 1L; private static final Natural INSTANCE = new Natural<>(); // hidden private Natural() { } @SuppressWarnings("unchecked") public static Natural instance() { return (Natural) INSTANCE; } @SuppressWarnings("unchecked") @Override public int compare(Tuple2 e1, Tuple2 e2) { final K key1 = e1._1; final K key2 = e2._1; return ((Comparable) key1).compareTo(key2); } @Override public Comparator keyComparator() { return naturalComparator(); } /** * Instance control for object serialization. * * @return The singleton instance of NaturalEntryComparator. * @see java.io.Serializable */ private Object readResolve() { return INSTANCE; } } } }