Pair.java

  1. /*
  2.  * *************************************************************************************************************************************************************
  3.  *
  4.  * TheseFoolishThings: Miscellaneous utilities
  5.  * http://tidalwave.it/projects/thesefoolishthings
  6.  *
  7.  * Copyright (C) 2009 - 2024 by Tidalwave s.a.s. (http://tidalwave.it)
  8.  *
  9.  * *************************************************************************************************************************************************************
  10.  *
  11.  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
  12.  * You may obtain a copy of the License at
  13.  *
  14.  *     http://www.apache.org/licenses/LICENSE-2.0
  15.  *
  16.  * 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
  17.  * CONDITIONS OF ANY KIND, either express or implied.  See the License for the specific language governing permissions and limitations under the License.
  18.  *
  19.  * *************************************************************************************************************************************************************
  20.  *
  21.  * git clone https://bitbucket.org/tidalwave/thesefoolishthings-src
  22.  * git clone https://github.com/tidalwave-it/thesefoolishthings-src
  23.  *
  24.  * *************************************************************************************************************************************************************
  25.  */
  26. package it.tidalwave.util;

  27. import javax.annotation.Nonnegative;
  28. import javax.annotation.Nonnull;
  29. import javax.annotation.concurrent.Immutable;
  30. import javax.annotation.concurrent.NotThreadSafe;
  31. import java.util.Map;
  32. import java.util.concurrent.atomic.AtomicInteger;
  33. import java.util.function.IntFunction;
  34. import java.util.function.IntUnaryOperator;
  35. import java.util.stream.Collector;
  36. import java.util.stream.Collectors;
  37. import java.util.stream.IntStream;
  38. import java.util.stream.Stream;
  39. import java.util.stream.StreamSupport;
  40. import lombok.EqualsAndHashCode;
  41. import lombok.Getter;
  42. import lombok.RequiredArgsConstructor;
  43. import lombok.ToString;

  44. /***************************************************************************************************************************************************************
  45.  *
  46.  * A value object that contains a pair of values. Some factory methods allow creating pairs out of existing collections
  47.  * or arrays associating an index.
  48.  *
  49.  * @author  Fabrizio Giudici
  50.  * @since   3.2-ALPHA-6
  51.  * @it.tidalwave.javadoc.draft
  52.  *
  53.  **************************************************************************************************************************************************************/
  54. @Getter @Immutable @RequiredArgsConstructor(staticName = "of") @ToString @EqualsAndHashCode
  55. public class Pair<A, B>
  56.   {
  57.     /** A base 0 index rebaser. */
  58.     public static final IntUnaryOperator BASE_0 = i -> i;

  59.     /** A base 1 index rebaser. */
  60.     public static final IntUnaryOperator BASE_1 = i -> i + 1;

  61.     @Nonnull
  62.     public final A a;

  63.     @Nonnull
  64.     public final B b;

  65.     /***********************************************************************************************************************************************************
  66.      * Creates a {@link Stream} of {@code Pair}s composed of a given fixed value and another element taken from another
  67.      * {@link Stream}.
  68.      *
  69.      * @param   <T>     the type of the value
  70.      * @param   <U>     the type of the {@code Stream}
  71.      * @param   value   the value
  72.      * @param   stream  the {@code Stream}
  73.      * @return          the {@code Stream} of {@code Pair}s
  74.      * @since           3.2-ALPHA-12
  75.      **********************************************************************************************************************************************************/
  76.     @Nonnull
  77.     public static <T, U> Stream<Pair<T, U>> pairStream (@Nonnull final T value,
  78.                                                         @Nonnull final Stream<? extends U> stream)
  79.       {
  80.         return stream.map(object -> Pair.of(value, object));
  81.       }

  82.     /***********************************************************************************************************************************************************
  83.      * Creates a {@link Stream} of {@code Pair}s composed of a given fixed value and an integer in the given range.
  84.      *
  85.      * @param   <T>     the type of the value
  86.      * @param   value   the value
  87.      * @param   from    the first value of the integer {@code Stream} (included)
  88.      * @param   to      the last value of the integer {@code Stream} (excluded)
  89.      * @return          the {@code Stream} of {@code Pair}s
  90.      * @since           3.2-ALPHA-12
  91.      **********************************************************************************************************************************************************/
  92.     @Nonnull
  93.     public static <T> Stream<Pair<T, Integer>> pairRange (@Nonnull final T value,
  94.                                                           @Nonnegative final int from,
  95.                                                           @Nonnegative final int to)
  96.       {
  97.         return pairStream(value, IntStream.range(from, to).boxed());
  98.       }

  99.     /***********************************************************************************************************************************************************
  100.      * Creates a {@link Stream} of {@code Pair}s composed of a given fixed value and an integer in the given range.
  101.      *
  102.      * @param   <T>     the type of the value
  103.      * @param   value   the value
  104.      * @param   from    the first value of the integer {@code Stream} (included)
  105.      * @param   to      the last value of the integer {@code Stream} (included)
  106.      * @return          the {@code Stream} of {@code Pair}s
  107.      * @since           3.2-ALPHA-12
  108.      **********************************************************************************************************************************************************/
  109.     @Nonnull
  110.     public static <T> Stream<Pair<T, Integer>> pairRangeClosed (@Nonnull final T value,
  111.                                                                 @Nonnegative final int from,
  112.                                                                 @Nonnegative final int to)
  113.       {
  114.         return pairStream(value, IntStream.rangeClosed(from, to).boxed());
  115.       }

  116.     /***********************************************************************************************************************************************************
  117.      * Returns a {@link Stream} out of the elements in a given array made of {@link Pair}s {@code (index, value)}.
  118.      *
  119.      * @param       <T>             the type of the elements
  120.      * @param       array           the array
  121.      * @return                      the stream
  122.      **********************************************************************************************************************************************************/
  123.     @Nonnull
  124.     public static <T> Stream<Pair<Integer, T>> indexedPairStream (@Nonnull final T[] array)
  125.       {
  126.         return indexedPairStream(array, BASE_0);
  127.       }

  128.     /***********************************************************************************************************************************************************
  129.      * Returns a {@link Stream} out of the elements in the array, made of {@link Pair}s {@code (index, value)}. The
  130.      * index can be rebased.
  131.      *
  132.      * @param       <T>               the type of the elements
  133.      * @param       array             the array
  134.      * @param       rebaser           the rebaser of the index (BASE_0, BASE_1 or a similar function)
  135.      * @return                        the stream
  136.      **********************************************************************************************************************************************************/
  137.     @Nonnull
  138.     public static <T> Stream<Pair<Integer, T>> indexedPairStream (@Nonnull final T[] array,
  139.                                                                   @Nonnull final IntUnaryOperator rebaser)
  140.       {
  141.         return indexedPairStream(array, rebaser, i -> i);
  142.       }

  143.     /***********************************************************************************************************************************************************
  144.      * Returns a {@link Stream} out of the elements in a given array made of {@link Pair}s {@code (index, value)}. The
  145.      * index is transformed with the given function.
  146.      *
  147.      * @param       <I>               the type of the transformed index
  148.      * @param       <T>               the type of the elements
  149.      * @param       array             the array
  150.      * @param       indexTransformer  the transformer of the index
  151.      * @return                        the stream
  152.      **********************************************************************************************************************************************************/
  153.     @Nonnull
  154.     public static <I, T> Stream<Pair<I, T>> indexedPairStream (@Nonnull final T[] array,
  155.                                                                @Nonnull final IntFunction<? extends I> indexTransformer)
  156.       {
  157.         return indexedPairStream(array, BASE_0, indexTransformer);
  158.       }

  159.     /***********************************************************************************************************************************************************
  160.      * Returns a {@link Stream} out of the elements in the array, made of {@link Pair}s {@code (index, value)}.  The
  161.      * index can be rebased and transformed with specific functions.
  162.      *
  163.      * @param       <T>               the type of the elements
  164.      * @param       <I>               the type of the transformed index
  165.      * @param       array             the array
  166.      * @param       rebaser           the rebaser of the index (BASE_0, BASE_1 or a similar function)
  167.      * @param       indexTransformer  the transformer of the index
  168.      * @return                        the stream
  169.      **********************************************************************************************************************************************************/
  170.     @Nonnull
  171.     public static <T, I> Stream<Pair<I, T>> indexedPairStream (@Nonnull final T[] array,
  172.                                                                @Nonnull final IntUnaryOperator rebaser,
  173.                                                                @Nonnull final IntFunction<? extends I> indexTransformer)
  174.       {
  175.         return IntStream.range(0, array.length).mapToObj(i -> of(indexTransformer.apply(rebaser.applyAsInt(i)), array[i]));
  176.       }

  177.     /***********************************************************************************************************************************************************
  178.      * Returns a {@link Stream} out of the elements in a given {@link Iterable} made of {@link Pair}s {@code (index,
  179.      * value)}.
  180.      *
  181.      * @param       <T>             the type of the elements
  182.      * @param       iterable        the iterable
  183.      * @return                      the stream
  184.      **********************************************************************************************************************************************************/
  185.     @Nonnull
  186.     public static <T> Stream<Pair<Integer, T>> indexedPairStream (@Nonnull final Iterable<? extends T> iterable)
  187.       {
  188.         return indexedPairStream(iterable, BASE_0);
  189.       }

  190.     /***********************************************************************************************************************************************************
  191.      * Returns a {@link Stream} out of the elements in a given {@link Iterable} made of {@link Pair}s {@code (index,
  192.      * value)}. The index can be rebased.
  193.      *
  194.      * @param       <T>               the type of the elements
  195.      * @param       iterable          the iterable
  196.      * @param       rebaser           the rebaser of the index (BASE_0, BASE_1 or a similar function)
  197.      * @return                        the stream
  198.      **********************************************************************************************************************************************************/
  199.     @Nonnull
  200.     public static <T> Stream<Pair<Integer, T>> indexedPairStream (@Nonnull final Iterable<? extends T> iterable,
  201.                                                                   @Nonnull final IntUnaryOperator rebaser)
  202.       {
  203.         return indexedPairStream(iterable, rebaser, i -> i);
  204.       }

  205.     /***********************************************************************************************************************************************************
  206.      * Returns a {@link Stream} out of the elements in a given {@link Iterable} made of {@link Pair}s {@code (index,
  207.      * value)}. The index is transformed with the given function.
  208.      *
  209.      * @param       <I>               the type of the transformed index
  210.      * @param       <T>               the type of the elements
  211.      * @param       iterable          the iterable
  212.      * @param       indexTransformer  the transformer of the index
  213.      * @return                        the stream
  214.      **********************************************************************************************************************************************************/
  215.     @Nonnull
  216.     public static <I, T> Stream<Pair<I, T>> indexedPairStream (@Nonnull final Iterable<? extends T> iterable,
  217.                                                                @Nonnull final IntFunction<? extends I> indexTransformer)
  218.       {
  219.         return indexedPairStream(iterable, BASE_0, indexTransformer);
  220.       }

  221.     /***********************************************************************************************************************************************************
  222.      * Returns a {@link Stream} out of the elements returned by an iterable, made of {@link Pair}s
  223.      * {@code (index, value)}. The index is rebased and transformed with specific functions.
  224.      *
  225.      * @param       <T>               the type of the elements
  226.      * @param       <I>               the type of the transformed index
  227.      * @param       iterable          the iterable
  228.      * @param       rebaser           the rebaser of the index (BASE_0, BASE_1 or a similar function)
  229.      * @param       indexTransformer  the transformer of the index
  230.      * @return                        the stream
  231.      **********************************************************************************************************************************************************/
  232.     @Nonnull
  233.     public static <I, T> Stream<Pair<I, T>> indexedPairStream (@Nonnull final Iterable<? extends T> iterable,
  234.                                                                @Nonnull final IntUnaryOperator rebaser,
  235.                                                                @Nonnull final IntFunction<? extends I> indexTransformer)
  236.       {
  237.         return new Factory<I, T>().stream(iterable, rebaser, indexTransformer);
  238.       }

  239.     /***********************************************************************************************************************************************************
  240.      * Returns a {@link Stream} out of the elements in a given {@link Stream} made of {@link Pair}s {@code (index,
  241.      * value)}.
  242.      *
  243.      * @param       <T>             the type of the elements
  244.      * @param       stream          the stream
  245.      * @return                      the stream
  246.      * @since       3.2-ALPHA-12
  247.      **********************************************************************************************************************************************************/
  248.     @Nonnull @SuppressWarnings("unchecked")
  249.     public static <T> Stream<Pair<Integer, T>> indexedPairStream (@Nonnull final Stream<? extends T> stream)
  250.       {
  251.         return indexedPairStream(((Stream<T>)stream)::iterator);
  252.       }

  253.     /***********************************************************************************************************************************************************
  254.      * Returns a {@link Stream} out of the elements in a given {@link Stream} made of {@link Pair}s {@code (index,
  255.      * value)}. The index can be rebased.
  256.      *
  257.      * @param       <T>               the type of the elements
  258.      * @param       stream            the stream
  259.      * @param       rebaser           the rebaser of the index (BASE_0, BASE_1 or a similar function)
  260.      * @return                        the stream
  261.      * @since       3.2-ALPHA-12
  262.      **********************************************************************************************************************************************************/
  263.     @Nonnull @SuppressWarnings("unchecked")
  264.     public static <T> Stream<Pair<Integer, T>> indexedPairStream (@Nonnull final Stream<? extends T> stream,
  265.                                                                   @Nonnull final IntUnaryOperator rebaser)
  266.       {
  267.         return indexedPairStream(((Stream<T>)stream)::iterator, rebaser);
  268.       }

  269.     /***********************************************************************************************************************************************************
  270.      * Returns a {@link Stream} out of the elements in a given {@link Stream} made of {@link Pair}s {@code (index,
  271.      * value)}. The index is transformed with the given function.
  272.      *
  273.      * @param       <I>               the type of the transformed index
  274.      * @param       <T>               the type of the elements
  275.      * @param       stream            the stream
  276.      * @param       indexTransformer  the transformer of the index
  277.      * @return                        the stream
  278.      * @since       3.2-ALPHA-12
  279.      **********************************************************************************************************************************************************/
  280.     @SuppressWarnings("unchecked")
  281.     @Nonnull
  282.     public static <I, T> Stream<Pair<I, T>> indexedPairStream (@Nonnull final Stream<? extends T> stream,
  283.                                                                @Nonnull final IntFunction<? extends I> indexTransformer)
  284.       {
  285.         return indexedPairStream(((Stream<T>)stream)::iterator, indexTransformer);
  286.       }

  287.     /***********************************************************************************************************************************************************
  288.      * Returns a {@link Stream} out of the elements returned by a Stream, made of {@link Pair}s
  289.      * {@code (index, value)}. The index is rebased and transformed with specific functions.
  290.      *
  291.      * @param       <T>               the type of the elements
  292.      * @param       <I>               the type of the transformed index
  293.      * @param       stream            the stream
  294.      * @param       rebaser           the rebaser of the index (BASE_0, BASE_1 or a similar function)
  295.      * @param       indexTransformer  the transformer of the index
  296.      * @return                        the stream
  297.      * @since       3.2-ALPHA-12
  298.      **********************************************************************************************************************************************************/
  299.     @SuppressWarnings("unchecked")
  300.     @Nonnull
  301.     public static <I, T> Stream<Pair<I, T>> indexedPairStream (@Nonnull final Stream<? extends T> stream,
  302.                                                                @Nonnull final IntUnaryOperator rebaser,
  303.                                                                @Nonnull final IntFunction<? extends I> indexTransformer)
  304.       {
  305.         return indexedPairStream(((Stream<T>)stream)::iterator, rebaser, indexTransformer);
  306.       }

  307.     /***********************************************************************************************************************************************************
  308.      * Returns a {@link Stream} out of the elements returned by a supplier, made of {@link Pair}s
  309.      * {@code (index, value)}.
  310.      *
  311.      * @param       <T>               the type of the elements
  312.      * @param       from              the first index (included)
  313.      * @param       to                the last index (excluded)
  314.      * @param       valueSupplier     the supplier of values
  315.      * @return                        the stream
  316.      **********************************************************************************************************************************************************/
  317.     @Nonnull
  318.     public static <T> Stream<Pair<Integer, T>> indexedPairStream (@Nonnegative final int from,
  319.                                                                   @Nonnegative final int to,
  320.                                                                   @Nonnull final IntFunction<? extends T> valueSupplier)
  321.       {
  322.         return indexedPairStream(from, to, valueSupplier, BASE_0, i -> i);
  323.       }

  324.     /***********************************************************************************************************************************************************
  325.      * Returns a {@link Stream} out of the elements returned by a supplier, made of {@link Pair}s
  326.      * {@code (index, value)}.
  327.      *
  328.      * @param       <T>               the type of the elements
  329.      * @param       from              the first index (included)
  330.      * @param       to                the last index (excluded)
  331.      * @param       valueSupplier     the supplier of values
  332.      * @param       rebaser           the rebaser of the index (BASE_0, BASE_1 or a similar function)
  333.      * @return                        the stream
  334.      **********************************************************************************************************************************************************/
  335.     @Nonnull
  336.     public static <T> Stream<Pair<Integer, T>> indexedPairStream (@Nonnegative final int from,
  337.                                                                   @Nonnegative final int to,
  338.                                                                   @Nonnull final IntFunction<? extends T> valueSupplier,
  339.                                                                   @Nonnull final IntUnaryOperator rebaser)
  340.       {
  341.         return indexedPairStream(from, to, valueSupplier, rebaser, i -> i);
  342.       }

  343.     /***********************************************************************************************************************************************************
  344.      * Returns a {@link Stream} out of the elements returned by a supplier, made of {@link Pair}s
  345.      * {@code (index, value)}. The index can be rebased and transformed with specific functions.
  346.      *
  347.      * @param       <I>               the type of the transformed index
  348.      * @param       <T>               the type of the elements
  349.      * @param       from              the first index (included)
  350.      * @param       to                the last index (excluded)
  351.      * @param       valueSupplier     the supplier of values
  352.      * @param       rebaser           the rebaser of the index (BASE_0, BASE_1 or a similar function)
  353.      * @param       indexTransformer  the transformer of the index
  354.      * @return                        the stream
  355.      **********************************************************************************************************************************************************/
  356.     @Nonnull
  357.     public static <T, I> Stream<Pair<I, T>> indexedPairStream (@Nonnegative final int from,
  358.                                                                @Nonnegative final int to,
  359.                                                                @Nonnull final IntFunction<? extends T> valueSupplier,
  360.                                                                @Nonnull final IntUnaryOperator rebaser,
  361.                                                                @Nonnull final IntFunction<? extends I> indexTransformer)
  362.       {
  363.         return IntStream.range(from, to).mapToObj(i -> Pair.of(indexTransformer.apply(rebaser.applyAsInt(i)),
  364.                                                                valueSupplier.apply(i)));
  365.       }

  366.     /***********************************************************************************************************************************************************
  367.      * A {@link Collector} that produces a {@link Map} whose key is field {@code a} and value field {@code b}. Use
  368.      * with {@link Stream#collect(Collector)}.
  369.      *
  370.      * @param <A>   the type of the former element of the pair
  371.      * @param <B>   the type of the latter element of the pair
  372.      * @return      the {@code Collector}
  373.      **********************************************************************************************************************************************************/
  374.     @Nonnull
  375.     public static <A, B> Collector<Pair<A, B>, ?, Map<A, B>> pairsToMap()
  376.       {
  377.         return Collectors.toMap(p -> p.a, p -> p.b);
  378.       }

  379.     /***********************************************************************************************************************************************************
  380.      * Zips two streams into a stream of {@link Pair}s.
  381.      *
  382.      * @param   streamA     the first {@link Stream}
  383.      * @param   streamB     the second {@link Stream}
  384.      * @param   <A>         the type of elements of the first {@link Stream}
  385.      * @param   <B>         the type of elements of the second {@link Stream}
  386.      * @return              the zipped {@link Stream}
  387.      * @since   3.2-ALPHA-17 (since 3.2-ALPHA-12 was in {@code StreamOperations}
  388.      **********************************************************************************************************************************************************/
  389.     @Nonnull
  390.     public static <A, B> Stream<Pair<A, B>> zip (@Nonnull final Stream<? extends A> streamA,
  391.                                                  @Nonnull final Stream<? extends B> streamB)
  392.       {
  393.         return StreamUtils.zip(streamA, streamB);
  394.       }

  395.     @NotThreadSafe
  396.     static final class Factory<I, T>
  397.       {
  398.         private final AtomicInteger n = new AtomicInteger(0);

  399.         @Nonnull
  400.         public Stream<Pair<I, T>> stream (@Nonnull final Iterable<? extends T> iterable,
  401.                                           @Nonnull final IntUnaryOperator rebaser,
  402.                                           @Nonnull final IntFunction<? extends I> indexFunction)
  403.           {
  404.             return StreamSupport.stream(iterable.spliterator(), false)
  405.                                 .map(o -> Pair.of(indexFunction.apply(rebaser.applyAsInt(n.getAndIncrement())), o));
  406.           }
  407.       }
  408.   }