View Javadoc
1   /*
2    * *************************************************************************************************************************************************************
3    *
4    * TheseFoolishThings: Miscellaneous utilities
5    * http://tidalwave.it/projects/thesefoolishthings
6    *
7    * Copyright (C) 2009 - 2025 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  
28  import javax.annotation.Nonnegative;
29  import javax.annotation.concurrent.Immutable;
30  import javax.annotation.concurrent.NotThreadSafe;
31  import jakarta.annotation.Nonnull;
32  import java.util.Map;
33  import java.util.concurrent.atomic.AtomicInteger;
34  import java.util.function.IntFunction;
35  import java.util.function.IntUnaryOperator;
36  import java.util.stream.Collector;
37  import java.util.stream.Collectors;
38  import java.util.stream.IntStream;
39  import java.util.stream.Stream;
40  import java.util.stream.StreamSupport;
41  import lombok.EqualsAndHashCode;
42  import lombok.Getter;
43  import lombok.RequiredArgsConstructor;
44  import lombok.ToString;
45  
46  /***************************************************************************************************************************************************************
47   *
48   * A value object that contains a pair of values. Some factory methods allow creating pairs out of existing collections
49   * or arrays associating an index.
50   *
51   * @author  Fabrizio Giudici
52   * @since   3.2-ALPHA-6
53   * @it.tidalwave.javadoc.draft
54   *
55   **************************************************************************************************************************************************************/
56  @Getter @Immutable @RequiredArgsConstructor(staticName = "of") @ToString @EqualsAndHashCode
57  public class Pair<A, B>
58    {
59      /** A base 0 index rebaser. */
60      public static final IntUnaryOperator BASE_0 = i -> i;
61  
62      /** A base 1 index rebaser. */
63      public static final IntUnaryOperator BASE_1 = i -> i + 1;
64  
65      @Nonnull
66      public final A a;
67  
68      @Nonnull
69      public final B b;
70  
71      /***********************************************************************************************************************************************************
72       * Creates a {@link Stream} of {@code Pair}s composed of a given fixed value and another element taken from another
73       * {@link Stream}.
74       *
75       * @param   <T>     the type of the value
76       * @param   <U>     the type of the {@code Stream}
77       * @param   value   the value
78       * @param   stream  the {@code Stream}
79       * @return          the {@code Stream} of {@code Pair}s
80       * @since           3.2-ALPHA-12
81       **********************************************************************************************************************************************************/
82      @Nonnull
83      public static <T, U> Stream<Pair<T, U>> pairStream (@Nonnull final T value,
84                                                          @Nonnull final Stream<? extends U> stream)
85        {
86          return stream.map(object -> Pair.of(value, object));
87        }
88  
89      /***********************************************************************************************************************************************************
90       * Creates a {@link Stream} of {@code Pair}s composed of a given fixed value and an integer in the given range.
91       *
92       * @param   <T>     the type of the value
93       * @param   value   the value
94       * @param   from    the first value of the integer {@code Stream} (included)
95       * @param   to      the last value of the integer {@code Stream} (excluded)
96       * @return          the {@code Stream} of {@code Pair}s
97       * @since           3.2-ALPHA-12
98       **********************************************************************************************************************************************************/
99      @Nonnull
100     public static <T> Stream<Pair<T, Integer>> pairRange (@Nonnull final T value,
101                                                           @Nonnegative final int from,
102                                                           @Nonnegative final int to)
103       {
104         return pairStream(value, IntStream.range(from, to).boxed());
105       }
106 
107     /***********************************************************************************************************************************************************
108      * Creates a {@link Stream} of {@code Pair}s composed of a given fixed value and an integer in the given range.
109      *
110      * @param   <T>     the type of the value
111      * @param   value   the value
112      * @param   from    the first value of the integer {@code Stream} (included)
113      * @param   to      the last value of the integer {@code Stream} (included)
114      * @return          the {@code Stream} of {@code Pair}s
115      * @since           3.2-ALPHA-12
116      **********************************************************************************************************************************************************/
117     @Nonnull
118     public static <T> Stream<Pair<T, Integer>> pairRangeClosed (@Nonnull final T value,
119                                                                 @Nonnegative final int from,
120                                                                 @Nonnegative final int to)
121       {
122         return pairStream(value, IntStream.rangeClosed(from, to).boxed());
123       }
124 
125     /***********************************************************************************************************************************************************
126      * Returns a {@link Stream} out of the elements in a given array made of {@link Pair}s {@code (index, value)}.
127      *
128      * @param       <T>             the type of the elements
129      * @param       array           the array
130      * @return                      the stream
131      **********************************************************************************************************************************************************/
132     @Nonnull
133     public static <T> Stream<Pair<Integer, T>> indexedPairStream (@Nonnull final T[] array)
134       {
135         return indexedPairStream(array, BASE_0);
136       }
137 
138     /***********************************************************************************************************************************************************
139      * Returns a {@link Stream} out of the elements in the array, made of {@link Pair}s {@code (index, value)}. The
140      * index can be rebased.
141      *
142      * @param       <T>               the type of the elements
143      * @param       array             the array
144      * @param       rebaser           the rebaser of the index (BASE_0, BASE_1 or a similar function)
145      * @return                        the stream
146      **********************************************************************************************************************************************************/
147     @Nonnull
148     public static <T> Stream<Pair<Integer, T>> indexedPairStream (@Nonnull final T[] array,
149                                                                   @Nonnull final IntUnaryOperator rebaser)
150       {
151         return indexedPairStream(array, rebaser, i -> i);
152       }
153 
154     /***********************************************************************************************************************************************************
155      * Returns a {@link Stream} out of the elements in a given array made of {@link Pair}s {@code (index, value)}. The
156      * index is transformed with the given function.
157      *
158      * @param       <I>               the type of the transformed index
159      * @param       <T>               the type of the elements
160      * @param       array             the array
161      * @param       indexTransformer  the transformer of the index
162      * @return                        the stream
163      **********************************************************************************************************************************************************/
164     @Nonnull
165     public static <I, T> Stream<Pair<I, T>> indexedPairStream (@Nonnull final T[] array,
166                                                                @Nonnull final IntFunction<? extends I> indexTransformer)
167       {
168         return indexedPairStream(array, BASE_0, indexTransformer);
169       }
170 
171     /***********************************************************************************************************************************************************
172      * Returns a {@link Stream} out of the elements in the array, made of {@link Pair}s {@code (index, value)}.  The
173      * index can be rebased and transformed with specific functions.
174      *
175      * @param       <T>               the type of the elements
176      * @param       <I>               the type of the transformed index
177      * @param       array             the array
178      * @param       rebaser           the rebaser of the index (BASE_0, BASE_1 or a similar function)
179      * @param       indexTransformer  the transformer of the index
180      * @return                        the stream
181      **********************************************************************************************************************************************************/
182     @Nonnull
183     public static <T, I> Stream<Pair<I, T>> indexedPairStream (@Nonnull final T[] array,
184                                                                @Nonnull final IntUnaryOperator rebaser,
185                                                                @Nonnull final IntFunction<? extends I> indexTransformer)
186       {
187         return IntStream.range(0, array.length).mapToObj(i -> of(indexTransformer.apply(rebaser.applyAsInt(i)), array[i]));
188       }
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)}.
193      *
194      * @param       <T>             the type of the elements
195      * @param       iterable        the iterable
196      * @return                      the stream
197      **********************************************************************************************************************************************************/
198     @Nonnull
199     public static <T> Stream<Pair<Integer, T>> indexedPairStream (@Nonnull final Iterable<? extends T> iterable)
200       {
201         return indexedPairStream(iterable, BASE_0);
202       }
203 
204     /***********************************************************************************************************************************************************
205      * Returns a {@link Stream} out of the elements in a given {@link Iterable} made of {@link Pair}s {@code (index,
206      * value)}. The index can be rebased.
207      *
208      * @param       <T>               the type of the elements
209      * @param       iterable          the iterable
210      * @param       rebaser           the rebaser of the index (BASE_0, BASE_1 or a similar function)
211      * @return                        the stream
212      **********************************************************************************************************************************************************/
213     @Nonnull
214     public static <T> Stream<Pair<Integer, T>> indexedPairStream (@Nonnull final Iterable<? extends T> iterable,
215                                                                   @Nonnull final IntUnaryOperator rebaser)
216       {
217         return indexedPairStream(iterable, rebaser, i -> i);
218       }
219 
220     /***********************************************************************************************************************************************************
221      * Returns a {@link Stream} out of the elements in a given {@link Iterable} made of {@link Pair}s {@code (index,
222      * value)}. The index is transformed with the given function.
223      *
224      * @param       <I>               the type of the transformed index
225      * @param       <T>               the type of the elements
226      * @param       iterable          the iterable
227      * @param       indexTransformer  the transformer of the index
228      * @return                        the stream
229      **********************************************************************************************************************************************************/
230     @Nonnull
231     public static <I, T> Stream<Pair<I, T>> indexedPairStream (@Nonnull final Iterable<? extends T> iterable,
232                                                                @Nonnull final IntFunction<? extends I> indexTransformer)
233       {
234         return indexedPairStream(iterable, BASE_0, indexTransformer);
235       }
236 
237     /***********************************************************************************************************************************************************
238      * Returns a {@link Stream} out of the elements returned by an iterable, made of {@link Pair}s
239      * {@code (index, value)}. The index is rebased and transformed with specific functions.
240      *
241      * @param       <T>               the type of the elements
242      * @param       <I>               the type of the transformed index
243      * @param       iterable          the iterable
244      * @param       rebaser           the rebaser of the index (BASE_0, BASE_1 or a similar function)
245      * @param       indexTransformer  the transformer of the index
246      * @return                        the stream
247      **********************************************************************************************************************************************************/
248     @Nonnull
249     public static <I, T> Stream<Pair<I, T>> indexedPairStream (@Nonnull final Iterable<? extends T> iterable,
250                                                                @Nonnull final IntUnaryOperator rebaser,
251                                                                @Nonnull final IntFunction<? extends I> indexTransformer)
252       {
253         return new Factory<I, T>().stream(iterable, rebaser, indexTransformer);
254       }
255 
256     /***********************************************************************************************************************************************************
257      * Returns a {@link Stream} out of the elements in a given {@link Stream} made of {@link Pair}s {@code (index,
258      * value)}.
259      *
260      * @param       <T>             the type of the elements
261      * @param       stream          the stream
262      * @return                      the stream
263      * @since       3.2-ALPHA-12
264      **********************************************************************************************************************************************************/
265     @Nonnull @SuppressWarnings("unchecked")
266     public static <T> Stream<Pair<Integer, T>> indexedPairStream (@Nonnull final Stream<? extends T> stream)
267       {
268         return indexedPairStream(((Stream<T>)stream)::iterator);
269       }
270 
271     /***********************************************************************************************************************************************************
272      * Returns a {@link Stream} out of the elements in a given {@link Stream} made of {@link Pair}s {@code (index,
273      * value)}. The index can be rebased.
274      *
275      * @param       <T>               the type of the elements
276      * @param       stream            the stream
277      * @param       rebaser           the rebaser of the index (BASE_0, BASE_1 or a similar function)
278      * @return                        the stream
279      * @since       3.2-ALPHA-12
280      **********************************************************************************************************************************************************/
281     @Nonnull @SuppressWarnings("unchecked")
282     public static <T> Stream<Pair<Integer, T>> indexedPairStream (@Nonnull final Stream<? extends T> stream,
283                                                                   @Nonnull final IntUnaryOperator rebaser)
284       {
285         return indexedPairStream(((Stream<T>)stream)::iterator, rebaser);
286       }
287 
288     /***********************************************************************************************************************************************************
289      * Returns a {@link Stream} out of the elements in a given {@link Stream} made of {@link Pair}s {@code (index,
290      * value)}. The index is transformed with the given function.
291      *
292      * @param       <I>               the type of the transformed index
293      * @param       <T>               the type of the elements
294      * @param       stream            the stream
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 IntFunction<? extends I> indexTransformer)
303       {
304         return indexedPairStream(((Stream<T>)stream)::iterator, indexTransformer);
305       }
306 
307     /***********************************************************************************************************************************************************
308      * Returns a {@link Stream} out of the elements returned by a Stream, made of {@link Pair}s
309      * {@code (index, value)}. The index is rebased and transformed with specific functions.
310      *
311      * @param       <T>               the type of the elements
312      * @param       <I>               the type of the transformed index
313      * @param       stream            the stream
314      * @param       rebaser           the rebaser of the index (BASE_0, BASE_1 or a similar function)
315      * @param       indexTransformer  the transformer of the index
316      * @return                        the stream
317      * @since       3.2-ALPHA-12
318      **********************************************************************************************************************************************************/
319     @SuppressWarnings("unchecked")
320     @Nonnull
321     public static <I, T> Stream<Pair<I, T>> indexedPairStream (@Nonnull final Stream<? extends T> stream,
322                                                                @Nonnull final IntUnaryOperator rebaser,
323                                                                @Nonnull final IntFunction<? extends I> indexTransformer)
324       {
325         return indexedPairStream(((Stream<T>)stream)::iterator, rebaser, indexTransformer);
326       }
327 
328     /***********************************************************************************************************************************************************
329      * Returns a {@link Stream} out of the elements returned by a supplier, made of {@link Pair}s
330      * {@code (index, value)}.
331      *
332      * @param       <T>               the type of the elements
333      * @param       from              the first index (included)
334      * @param       to                the last index (excluded)
335      * @param       valueSupplier     the supplier of values
336      * @return                        the stream
337      **********************************************************************************************************************************************************/
338     @Nonnull
339     public static <T> Stream<Pair<Integer, T>> indexedPairStream (@Nonnegative final int from,
340                                                                   @Nonnegative final int to,
341                                                                   @Nonnull final IntFunction<? extends T> valueSupplier)
342       {
343         return indexedPairStream(from, to, valueSupplier, BASE_0, i -> i);
344       }
345 
346     /***********************************************************************************************************************************************************
347      * Returns a {@link Stream} out of the elements returned by a supplier, made of {@link Pair}s
348      * {@code (index, value)}.
349      *
350      * @param       <T>               the type of the elements
351      * @param       from              the first index (included)
352      * @param       to                the last index (excluded)
353      * @param       valueSupplier     the supplier of values
354      * @param       rebaser           the rebaser of the index (BASE_0, BASE_1 or a similar function)
355      * @return                        the stream
356      **********************************************************************************************************************************************************/
357     @Nonnull
358     public static <T> Stream<Pair<Integer, T>> indexedPairStream (@Nonnegative final int from,
359                                                                   @Nonnegative final int to,
360                                                                   @Nonnull final IntFunction<? extends T> valueSupplier,
361                                                                   @Nonnull final IntUnaryOperator rebaser)
362       {
363         return indexedPairStream(from, to, valueSupplier, rebaser, i -> i);
364       }
365 
366     /***********************************************************************************************************************************************************
367      * Returns a {@link Stream} out of the elements returned by a supplier, made of {@link Pair}s
368      * {@code (index, value)}. The index can be rebased and transformed with specific functions.
369      *
370      * @param       <I>               the type of the transformed index
371      * @param       <T>               the type of the elements
372      * @param       from              the first index (included)
373      * @param       to                the last index (excluded)
374      * @param       valueSupplier     the supplier of values
375      * @param       rebaser           the rebaser of the index (BASE_0, BASE_1 or a similar function)
376      * @param       indexTransformer  the transformer of the index
377      * @return                        the stream
378      **********************************************************************************************************************************************************/
379     @Nonnull
380     public static <T, I> Stream<Pair<I, T>> indexedPairStream (@Nonnegative final int from,
381                                                                @Nonnegative final int to,
382                                                                @Nonnull final IntFunction<? extends T> valueSupplier,
383                                                                @Nonnull final IntUnaryOperator rebaser,
384                                                                @Nonnull final IntFunction<? extends I> indexTransformer)
385       {
386         return IntStream.range(from, to).mapToObj(i -> Pair.of(indexTransformer.apply(rebaser.applyAsInt(i)),
387                                                                valueSupplier.apply(i)));
388       }
389 
390     /***********************************************************************************************************************************************************
391      * A {@link Collector} that produces a {@link Map} whose key is field {@code a} and value field {@code b}. Use
392      * with {@link Stream#collect(Collector)}.
393      *
394      * @param <A>   the type of the former element of the pair
395      * @param <B>   the type of the latter element of the pair
396      * @return      the {@code Collector}
397      **********************************************************************************************************************************************************/
398     @Nonnull
399     public static <A, B> Collector<Pair<A, B>, ?, Map<A, B>> pairsToMap()
400       {
401         return Collectors.toMap(p -> p.a, p -> p.b);
402       }
403 
404     /***********************************************************************************************************************************************************
405      * Zips two streams into a stream of {@link Pair}s.
406      *
407      * @param   streamA     the first {@link Stream}
408      * @param   streamB     the second {@link Stream}
409      * @param   <A>         the type of elements of the first {@link Stream}
410      * @param   <B>         the type of elements of the second {@link Stream}
411      * @return              the zipped {@link Stream}
412      * @since   3.2-ALPHA-17 (since 3.2-ALPHA-12 was in {@code StreamOperations}
413      **********************************************************************************************************************************************************/
414     @Nonnull
415     public static <A, B> Stream<Pair<A, B>> zip (@Nonnull final Stream<? extends A> streamA,
416                                                  @Nonnull final Stream<? extends B> streamB)
417       {
418         return StreamUtils.zip(streamA, streamB);
419       }
420 
421     @NotThreadSafe
422     static final class Factory<I, T>
423       {
424         private final AtomicInteger n = new AtomicInteger(0);
425 
426         @Nonnull
427         public Stream<Pair<I, T>> stream (@Nonnull final Iterable<? extends T> iterable,
428                                           @Nonnull final IntUnaryOperator rebaser,
429                                           @Nonnull final IntFunction<? extends I> indexFunction)
430           {
431             return StreamSupport.stream(iterable.spliterator(), false)
432                                 .map(o -> Pair.of(indexFunction.apply(rebaser.applyAsInt(n.getAndIncrement())), o));
433           }
434       }
435   }