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

net.yetamine.lang.containers.tuples.Tuple2 Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2016 Yetamine
 *
 * 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 net.yetamine.lang.containers.tuples;

import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import net.yetamine.lang.collections.Iterators;

/**
 * A rudimentary tuple implementation consisting of two elements.
 *
 * @param 
 *            the type of element #1
 * @param 
 *            the type of element #2
 */
public final class Tuple2 implements Tuple {

    /** Common shared empty tuple. */
    private static final Tuple2 EMPTY = new Tuple2<>(null, null);

    /** Element #1. */
    private final T1 value1;
    /** Element #2. */
    private final T2 value2;

    /**
     * Creates a new instance.
     *
     * @param t1
     *            element #1
     * @param t2
     *            element #2
     */
    private Tuple2(T1 t1, T2 t2) {
        value1 = t1;
        value2 = t2;
    }

    // Core construction methods

    /**
     * Creates a new instance.
     *
     * 

* This method is an alias for {@link #of(Object, Object)} and it is meant * mainly as a support for static imports. * * @param * the type of element #1 * @param * the type of element #2 * @param t1 * element #1 * @param t2 * element #2 * * @return the new instance */ public static Tuple2 tuple2(T1 t1, T2 t2) { return of(t1, t2); } /** * Creates a new instance. * * @param * the type of element #1 * @param * the type of element #2 * @param t1 * element #1 * @param t2 * element #2 * * @return the new instance */ public static Tuple2 of(T1 t1, T2 t2) { return new Tuple2<>(t1, t2); } /** * Returns an empty tuple (consisting of {@code null} elements). * * @param * the type of element #1 * @param * the type of element #2 * * @return an empty tuple */ @SuppressWarnings("unchecked") public static Tuple2 empty() { return (Tuple2) EMPTY; } /** * Narrows a widened type performing a safe type cast (thanks to the safe * covariant changes for immutable types). * * @param * the type of element #1 * @param * the type of element #2 * @param instance * the instance to narrow * * @return the narrowed instance */ @SuppressWarnings("unchecked") public static Tuple2 narrow(Tuple2 instance) { return (Tuple2) instance; } // Common object methods /** * @see java.lang.Object#toString() */ @Override public String toString() { return String.format("(%s, %s)", value1, value2); } /** * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof Tuple2) { final Tuple2 o = (Tuple2) obj; return Objects.equals(value1, o.value1) && Objects.equals(value2, o.value2); } return false; } /** * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return Objects.hash(value1, value2); } // Inherited methods /** * @see net.yetamine.lang.containers.tuples.Tuple#arity() */ public int arity() { return 2; } /** * @see net.yetamine.lang.containers.tuples.Tuple#get(int) */ public Object get(int index) { switch (index) { case 0: return get1(); case 1: return get2(); default: throw new IndexOutOfBoundsException(); } } /** * @see net.yetamine.lang.containers.tuples.Tuple#toList() */ public List toList() { return Collections.unmodifiableList(Arrays.asList(value1, value2)); } // Core tuple methods /** * Returns element #1. * * @return element #1 */ public T1 get1() { return value1; } /** * Returns element #2. * * @return element #2 */ public T2 get2() { return value2; } /** * Returns a tuple with element #1 modified to the given value. * * @param * the type of the value * @param value * the value to set * * @return a tuple with element #1 modified to the given value */ public Tuple2 set1(V value) { return of(value, value2); } /** * Returns a tuple with element #2 modified to the given value. * * @param * the type of the value * @param value * the value to set * * @return a tuple with element #2 modified to the given value */ public Tuple2 set2(V value) { return of(value1, value); } /** * Returns a tuple with swapped elements. * * @return a tuple with swapped elements */ public Tuple2 swap() { return (this == EMPTY) ? empty() : of(value2, value1); } // Link to Tuple3 /** * Makes a tuple with the given value prepended to this tuple. * * @param * the type of the value * @param value * the value to prepend * * @return a tuple with the given value prepended to this tuple */ public Tuple3 prepend(V value) { return Tuple3.of(value, value1, value2); } /** * Makes a tuple with the given value appended to this tuple. * * @param * the type of the value * @param value * the value to append * * @return a tuple with the given value appended to this tuple */ public Tuple3 append(V value) { return Tuple3.of(value1, value2, value); } /** * Makes a tuple with the given value inserted between the elements of this * tuple. * * @param * the type of the value * @param value * the value to insert * * @return a tuple with the given value inserted between the elements of * this tuple */ public Tuple3 insert(V value) { return Tuple3.of(value1, value, value2); } // Functional extensions /** * Returns a tuple with element #1 mapped with the given function. * * @param * the type of the function result * @param mapping * the function to apply. It must not be {@code null}. * * @return a tuple with element #1 mapped with the given function */ public Tuple2 map1(Function mapping) { return of(mapping.apply(value1), value2); } /** * Returns a tuple with element #2 mapped with the given function. * * @param * the type of the function result * @param mapping * the function to apply. It must not be {@code null}. * * @return a tuple with element #2 mapped with the given function */ public Tuple2 map2(Function mapping) { return of(value1, mapping.apply(value2)); } /** * Passes element #1 to the specified consumer. * * @param consumer * the consumer to call. It must not be {@code null}. * * @return this instance */ public Tuple2 use1(Consumer consumer) { consumer.accept(value1); return this; } /** * Passes element #2 to the specified consumer. * * @param consumer * the consumer to call. It must not be {@code null}. * * @return this instance */ public Tuple2 use2(Consumer consumer) { consumer.accept(value2); return this; } /** * Passes the elements of this tuple to the given {@link BiConsumer}. * * @param consumer * the consumer to apply on the elements. It must not be * {@code null}. * * @return this instance */ public Tuple2 use(BiConsumer consumer) { consumer.accept(value1, value2); return this; } /** * Applies the given function on the elements of this tuple and returns its * result. * * @param * the type of the result * @param mapping * the function to apply on the elements. It must not be * {@code null}. * * @return the result of the given function */ public V map(BiFunction mapping) { return mapping.apply(value1, value2); } // Factory methods for common types /** * Converts an {@link java.util.Map.Entry} instance into a tuple. * * @param * the type of the entry's key * @param * the type of the entry's value * @param entry * the entry to convert. It must not be {@code null}. * * @return a tuple containing the entry content */ public static Tuple2 from(Map.Entry entry) { return of(entry.getKey(), entry.getValue()); } /** * Makes a tuple from the first two elements provided by the given source. * * @param * the type of the source's elements * @param source * the source to process. It must provide at least two elements. * * @return a tuple * * @throws NoSuchElementException * if the source provides too few elements */ public static Tuple2 from(Iterable source) { return from(source.iterator()); } /** * Makes a tuple from the first two elements provided by the given source. * * @param * the type of the source's elements * @param source * the source to process. It must provide at least two elements. * * @return a tuple * * @throws NoSuchElementException * if the source provides too few elements */ public static Tuple2 from(Iterator source) { return of(source.next(), source.next()); } // Zipping /** * Returns an iterable zipping the elements from given source iterables. * *

* The resulting iterables returns tuples from the elements provided by the * source iterables and returns as many elements as the shorter of the * source iterables. * * @param * the type of element #1 * @param * the type of element #2 * @param source1 * the source of elements. It must not be {@code null}. * @param source2 * the source of elements. It must not be {@code null}. * * @return a zipping iterable */ public static Iterable> zip(Iterable source1, Iterable source2) { Objects.requireNonNull(source1); Objects.requireNonNull(source2); // Rather not make a lambda, it might change return new Iterable>() { /** * @see java.lang.Iterable#iterator() */ public Iterator> iterator() { return Tuple2.zip(source1.iterator(), source2.iterator()); } }; } /** * Returns an iterator zipping the elements from given source iterators. * *

* The resulting iterator returns tuples from the elements provided by the * source iterators and returns as many elements as the shorter of the * source iterators. * * @param * the type of element #1 * @param * the type of element #2 * @param source1 * the source of elements. It must not be {@code null}. * @param source2 * the source of elements. It must not be {@code null}. * * @return a zipping iterator */ public static Iterator> zip(Iterator source1, Iterator source2) { Objects.requireNonNull(source1); Objects.requireNonNull(source2); return new Iterator>() { /** * @see java.util.Iterator#hasNext() */ public boolean hasNext() { return source1.hasNext() && source2.hasNext(); } /** * @see java.util.Iterator#next() */ public Tuple2 next() { return Tuple2.of(source1.next(), source2.next()); } }; } /** * Returns a stream zipping the elements from given source streams. * *

* The resulting stream returns tuples from the elements provided by the * source streams and returns as many elements as the shorter of the source * streams. * * @param * the type of element #1 * @param * the type of element #2 * @param source1 * the source of elements. It must not be {@code null}. * @param source2 * the source of elements. It must not be {@code null}. * * @return a zipping stream */ public static Stream> zip(Stream source1, Stream source2) { return Iterators.stream(zip(source1.iterator(), source2.iterator())); } // Link to Map /** * Returns this instance as an immutable {@link Map}. * * @return this instance as an immutable {@link Map} */ public Map asMap() { return Collections.singletonMap(value1, value2); } /** * Provides the default {@link Collector} to collect a stream of tuples to a * map. * *

* This method is just a convenient shortcut for getting the suitable * collector using {@link Collectors#toMap(Function, Function)}. * * @param * the type of element #1 * @param * the type of element #2 * * @return a new collector */ public static Collector, ?, Map> toMap() { return Collectors.toMap(Tuple2::get1, Tuple2::get2); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy