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

org.apache.calcite.util.Pair Maven / Gradle / Ivy

There is a newer version: 1.21.0.263
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to you 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 org.apache.calcite.util;

import java.io.Serializable;
import java.util.AbstractList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nonnull;

/**
 * Pair of objects.
 *
 * 

Because a pair implements {@link #equals(Object)}, {@link #hashCode()} and * {@link #compareTo(Pair)}, it can be used in any kind of * {@link java.util.Collection}. * * @param Left-hand type * @param Right-hand type */ public class Pair implements Comparable>, Map.Entry, Serializable { //~ Instance fields -------------------------------------------------------- public final T1 left; public final T2 right; //~ Constructors ----------------------------------------------------------- /** * Creates a Pair. * * @param left left value * @param right right value */ public Pair(T1 left, T2 right) { this.left = left; this.right = right; } /** * Creates a Pair of appropriate type. * *

This is a shorthand that allows you to omit implicit types. For * example, you can write: *

return Pair.of(s, n);
* instead of *
return new Pair<String, Integer>(s, n);
* * @param left left value * @param right right value * @return A Pair */ public static Pair of(T1 left, T2 right) { return new Pair<>(left, right); } /** Creates a {@code Pair} from a {@link java.util.Map.Entry}. */ public static Pair of(Map.Entry entry) { return of(entry.getKey(), entry.getValue()); } //~ Methods ---------------------------------------------------------------- public boolean equals(Object obj) { return this == obj || (obj instanceof Pair) && Objects.equals(this.left, ((Pair) obj).left) && Objects.equals(this.right, ((Pair) obj).right); } /** {@inheritDoc} * *

Computes hash code consistent with * {@link java.util.Map.Entry#hashCode()}. */ @Override public int hashCode() { int keyHash = left == null ? 0 : left.hashCode(); int valueHash = right == null ? 0 : right.hashCode(); return keyHash ^ valueHash; } public int compareTo(@Nonnull Pair that) { //noinspection unchecked int c = compare((Comparable) this.left, (Comparable) that.left); if (c == 0) { //noinspection unchecked c = compare((Comparable) this.right, (Comparable) that.right); } return c; } public String toString() { return "<" + left + ", " + right + ">"; } public T1 getKey() { return left; } public T2 getValue() { return right; } public T2 setValue(T2 value) { throw new UnsupportedOperationException(); } /** * Compares a pair of comparable values of the same type. Null collates * less than everything else, but equal to itself. * * @param c1 First value * @param c2 Second value * @return a negative integer, zero, or a positive integer if c1 * is less than, equal to, or greater than c2. */ private static > int compare(C c1, C c2) { if (c1 == null) { if (c2 == null) { return 0; } else { return -1; } } else if (c2 == null) { return 1; } else { return c1.compareTo(c2); } } /** * Converts a collection of Pairs into a Map. * *

This is an obvious thing to do because Pair is similar in structure to * {@link java.util.Map.Entry}. * *

The map contains a copy of the collection of Pairs; if you change the * collection, the map does not change. * * @param pairs Collection of Pair objects * @return map with the same contents as the collection */ public static Map toMap(Iterable> pairs) { final Map map = new HashMap<>(); for (Pair pair : pairs) { map.put(pair.left, pair.right); } return map; } /** * Converts two lists into a list of {@link Pair}s, * whose length is the lesser of the lengths of the * source lists. * * @param ks Left list * @param vs Right list * @return List of pairs * @see org.apache.calcite.linq4j.Ord#zip(java.util.List) */ public static List> zip(List ks, List vs) { return zip(ks, vs, false); } /** * Converts two lists into a list of {@link Pair}s. * *

The length of the combined list is the lesser of the lengths of the * source lists. But typically the source lists will be the same length.

* * @param ks Left list * @param vs Right list * @param strict Whether to fail if lists have different size * @return List of pairs * @see org.apache.calcite.linq4j.Ord#zip(java.util.List) */ public static List> zip( final List ks, final List vs, boolean strict) { final int size; if (strict) { if (ks.size() != vs.size()) { throw new AssertionError(); } size = ks.size(); } else { size = Math.min(ks.size(), vs.size()); } return new ZipList<>(ks, vs, size); } /** * Converts two iterables into an iterable of {@link Pair}s. * *

The resulting iterator ends whenever the first of the input iterators * ends. But typically the source iterators will be the same length.

* * @param ks Left iterable * @param vs Right iterable * @return Iterable over pairs */ public static Iterable> zip( final Iterable ks, final Iterable vs) { return () -> { final Iterator kIterator = ks.iterator(); final Iterator vIterator = vs.iterator(); return new ZipIterator<>(kIterator, vIterator); }; } /** * Converts two arrays into a list of {@link Pair}s. * *

The length of the combined list is the lesser of the lengths of the * source arrays. But typically the source arrays will be the same * length.

* * @param ks Left array * @param vs Right array * @return List of pairs */ public static List> zip( final K[] ks, final V[] vs) { return new AbstractList>() { public Pair get(int index) { return Pair.of(ks[index], vs[index]); } public int size() { return Math.min(ks.length, vs.length); } }; } /** Returns a mutable list of pairs backed by a pair of mutable lists. * *

Modifications to this list are reflected in the backing lists, and vice * versa. * * @param Key (left) value type * @param Value (right) value type */ public static List> zipMutable( final List ks, final List vs) { return new MutableZipList<>(ks, vs); } /** * Returns an iterable over the left slice of an iterable. * * @param iterable Iterable over pairs * @param Left type * @param Right type * @return Iterable over the left elements */ public static Iterable left( final Iterable> iterable) { return () -> new LeftIterator<>(iterable.iterator()); } /** * Returns an iterable over the right slice of an iterable. * * @param iterable Iterable over pairs * @param right type * @param Right type * @return Iterable over the right elements */ public static Iterable right( final Iterable> iterable) { return () -> new RightIterator<>(iterable.iterator()); } public static List left( final List> pairs) { return new AbstractList() { public K get(int index) { return pairs.get(index).getKey(); } public int size() { return pairs.size(); } }; } public static List right( final List> pairs) { return new AbstractList() { public V get(int index) { return pairs.get(index).getValue(); } public int size() { return pairs.size(); } }; } /** * Returns an iterator that iterates over (i, i + 1) pairs in an iterable. * *

For example, {@code adjacents([3, 5, 7])} returns [(3, 5), (5, 7)].

* * @param iterable Source collection * @param Element type * @return Iterable over adjacent element pairs */ public static Iterable> adjacents(final Iterable iterable) { return () -> { final Iterator iterator = iterable.iterator(); if (!iterator.hasNext()) { return Collections.emptyIterator(); } return new AdjacentIterator<>(iterator); }; } /** * Returns an iterator that iterates over (0, i) pairs in an iterable for * i > 0. * *

For example, {@code firstAnd([3, 5, 7])} returns [(3, 5), (3, 7)].

* * @param iterable Source collection * @param Element type * @return Iterable over pairs of the first element and all other elements */ public static Iterable> firstAnd(final Iterable iterable) { return () -> { final Iterator iterator = iterable.iterator(); if (!iterator.hasNext()) { return Collections.emptyIterator(); } final T first = iterator.next(); return new FirstAndIterator<>(iterator, first); }; } /** Iterator that returns the left field of each pair. * * @param Left-hand type * @param Right-hand type */ private static class LeftIterator implements Iterator { private final Iterator> iterator; LeftIterator(Iterator> iterator) { this.iterator = Objects.requireNonNull(iterator); } public boolean hasNext() { return iterator.hasNext(); } public L next() { return iterator.next().getKey(); } public void remove() { iterator.remove(); } } /** Iterator that returns the right field of each pair. * * @param Left-hand type * @param Right-hand type */ private static class RightIterator implements Iterator { private final Iterator> iterator; RightIterator(Iterator> iterator) { this.iterator = Objects.requireNonNull(iterator); } public boolean hasNext() { return iterator.hasNext(); } public R next() { return iterator.next().getValue(); } public void remove() { iterator.remove(); } } /** Iterator that returns the first element of a collection paired with every * other element. * * @param Element type */ private static class FirstAndIterator implements Iterator> { private final Iterator iterator; private final E first; FirstAndIterator(Iterator iterator, E first) { this.iterator = Objects.requireNonNull(iterator); this.first = first; } public boolean hasNext() { return iterator.hasNext(); } public Pair next() { return of(first, iterator.next()); } public void remove() { throw new UnsupportedOperationException("remove"); } } /** Iterator that pairs elements from two iterators. * * @param Left-hand type * @param Right-hand type */ private static class ZipIterator implements Iterator> { private final Iterator leftIterator; private final Iterator rightIterator; ZipIterator(Iterator leftIterator, Iterator rightIterator) { this.leftIterator = Objects.requireNonNull(leftIterator); this.rightIterator = Objects.requireNonNull(rightIterator); } public boolean hasNext() { return leftIterator.hasNext() && rightIterator.hasNext(); } public Pair next() { return Pair.of(leftIterator.next(), rightIterator.next()); } public void remove() { leftIterator.remove(); rightIterator.remove(); } } /** Iterator that returns consecutive pairs of elements from an underlying * iterator. * * @param Element type */ private static class AdjacentIterator implements Iterator> { private final E first; private final Iterator iterator; E previous; AdjacentIterator(Iterator iterator) { this.iterator = Objects.requireNonNull(iterator); this.first = iterator.next(); previous = first; } public boolean hasNext() { return iterator.hasNext(); } public Pair next() { final E current = iterator.next(); final Pair pair = of(previous, current); previous = current; return pair; } public void remove() { throw new UnsupportedOperationException("remove"); } } /** Unmodifiable list of pairs, backed by a pair of lists. * *

Though it is unmodifiable, it is mutable: if the contents of one * of the backing lists changes, the contents of this list will appear to * change. The length, however, is fixed on creation. * * @param Left-hand type * @param Right-hand type * * @see MutableZipList */ private static class ZipList extends AbstractList> { private final List ks; private final List vs; private final int size; ZipList(List ks, List vs, int size) { this.ks = ks; this.vs = vs; this.size = size; } public Pair get(int index) { return Pair.of(ks.get(index), vs.get(index)); } public int size() { return size; } } /** A mutable list of pairs backed by a pair of mutable lists. * *

Modifications to this list are reflected in the backing lists, and vice * versa. * * @param Key (left) value type * @param Value (right) value type */ private static class MutableZipList extends AbstractList> { private final List ks; private final List vs; MutableZipList(List ks, List vs) { this.ks = Objects.requireNonNull(ks); this.vs = Objects.requireNonNull(vs); } @Override public Pair get(int index) { return Pair.of(ks.get(index), vs.get(index)); } @Override public int size() { return Math.min(ks.size(), vs.size()); } @Override public void add(int index, Pair pair) { ks.add(index, pair.left); vs.add(index, pair.right); } @Override public Pair remove(int index) { final K bufferedRow = ks.remove(index); final V stateSet = vs.remove(index); return Pair.of(bufferedRow, stateSet); } @Override public Pair set(int index, Pair pair) { final Pair previous = get(index); ks.set(index, pair.left); vs.set(index, pair.right); return previous; } } } // End Pair.java





© 2015 - 2024 Weber Informatics LLC | Privacy Policy