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.Nonnull; 30 import javax.annotation.concurrent.Immutable; 31 import javax.annotation.concurrent.NotThreadSafe; 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 }