Skip to content

Method: toString()

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