
net.yetamine.lang.containers.Tuple2 Maven / Gradle / Ivy
Show all versions of net.yetamine.lang Show documentation
package net.yetamine.lang.containers;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Spliterators;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/**
* A rudimentary tuple implementation consisting of two elements.
*
* @param
* the type of element #1
* @param
* the type of element #2
*/
public final class Tuple2 {
/** 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;
}
/**
* 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);
}
/**
* 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 extends K, ? extends V> 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 extends T> 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 extends T> source) {
return of(source.next(), source.next());
}
/**
* 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;
}
/**
* 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 extends T1> source1, Iterable extends T2> 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 extends T1> source1, Iterator extends T2> 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 extends T1> source1, Stream extends T2> source2) {
final Iterator> it = zip(source1.iterator(), source2.iterator());
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, 0), false);
}
/**
* @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);
}
/**
* 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 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 super T1, ? extends V> 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 super T2, ? extends V> 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 super T1> 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 super T2> consumer) {
consumer.accept(value2);
return this;
}
/**
* Returns a tuple with swapped elements.
*
* @return a tuple with swapped elements
*/
public Tuple2 swap() {
return (this == EMPTY) ? empty() : of(value2, value1);
}
/**
* Passes the elements of this tuple to the given {@link Consumer}.
*
* @param consumer
* the consumer to apply on the elements. It must not be
* {@code null}.
*/
public void accept(BiConsumer super T1, ? super T2> consumer) {
consumer.accept(value1, value2);
}
/**
* Applies the given function on the elements of this tuple and returns its
* result.
*
* @param
* the type of the result
* @param reduction
* the function to apply on the elements. It must not be
* {@code null}.
*
* @return the result of the given function
*/
public V reduce(BiFunction super T1, ? super T2, ? extends V> reduction) {
return reduction.apply(value1, value2);
}
/**
* 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);
}
}