001/* 002 * Java Genetic Algorithm Library (jenetics-7.2.0). 003 * Copyright (c) 2007-2023 Franz Wilhelmstötter 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 * 017 * Author: 018 * Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com) 019 */ 020package io.jenetics.util; 021 022import static java.util.Objects.checkFromToIndex; 023 024import java.util.List; 025 026/** 027 * This sorting methods doesn't sort a given array directly, instead 028 * an index lookup array is returned which allows to access the array in a 029 * sorted order. 030 * 031 * <pre>{@code 032 * final double[] array = new Random().doubles(100).toArray(); 033 * final int[] proxy = ProxySorter.sort(array); 034 * 035 * // 'Classical' array sort. 036 * final double[] sorted = array.clone(); 037 * Arrays.sort(sorted); 038 * 039 * // Iterating the array in ascending order. 040 * for (int i = 0; i < array.length; ++i) { 041 * assert sorted[i] == array[proxy[i]]; 042 * } 043 * }</pre> 044 * 045 * The minimal requirement of the proxy-sorter will be an access function and 046 * the number of elements you want to sort. 047 * <pre>{@code 048 * final IntFunction<String> access = ...; 049 * final int length = 100; 050 * final int[] proxy = ProxySorter.sort( 051 * access, length, 052 * (a, i, j) -> a.apply(i).compareTo(a.apply(j)) 053 * ); 054 * }</pre> 055 * @apiNote 056 * The most general sorting method is {@link #sort(Object, int, Comparator)}. 057 * All other sorting methods can be created with this method. 058 * 059 * @see #sort(Object, int, Comparator) 060 * @see Comparator 061 * 062 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 063 * @version 6.3 064 * @since 5.1 065 */ 066public final class ProxySorter { 067 068 /** 069 * The comparator used for comparing two array elements at the specified 070 * indexes. 071 * <pre>{@code 072 * final ProxySorter.Comparator<double[]> comparator = 073 * (a, i, j) -> Double.compare(a[i], a[j]); 074 * }</pre> 075 * The example above shows how to create a comparator for {@code double[]} 076 * arrays. 077 * 078 * @see ProxySorter#sort(Object, int, Comparator) 079 * @see ProxySorter 080 * 081 * @param <T> the array type, e.g. {@code int[]}, {@code double[]} or 082 * {@code Seq<String>} 083 * 084 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 085 * @version 5.1 086 * @since 5.1 087 */ 088 @FunctionalInterface 089 public interface Comparator<T> { 090 091 /** 092 * Compares the two array elements, specified by its indices, for order. 093 * Returns a negative integer, zero, or a positive integer as the first 094 * argument is less than, equal to, or greater than the second. 095 * 096 * @see java.util.Comparator#compare(Object, Object) 097 * 098 * @param array the array where the two comparing elements are fetched 099 * @param i the index of the first array element 100 * @param j the index of the second array element 101 * @return a negative integer, zero, or a positive integer as the first 102 * argument is less than, equal to, or greater than the second. 103 * @throws NullPointerException if an argument is null and this 104 * comparator does not permit null arguments 105 */ 106 int compare(final T array, final int i, final int j); 107 108 /** 109 * Returns a comparator that imposes the reverse ordering of this 110 * comparator. 111 * 112 * @return a comparator that imposes the reverse ordering of this 113 * comparator. 114 */ 115 default Comparator<T> reversed() { 116 return (a, i, j) -> compare(a, j, i); 117 } 118 119 } 120 121 @FunctionalInterface 122 interface Sorter<T> { 123 int[] sort( 124 final T array, 125 final int from, 126 final int to, 127 final Comparator<? super T> comparator 128 ); 129 130 default int[] sort( 131 final T array, 132 final int length, 133 final Comparator<? super T> comparator 134 ) { 135 return sort(array, 0, length, comparator); 136 } 137 } 138 139 private ProxySorter() { 140 } 141 142 /** 143 * Sorting the given array by creating an index lookup array. The original 144 * array is not touched, and the returned array can then be used for 145 * iterating the array in ascending order. 146 * 147 * <pre>{@code 148 * final double[] array = ...; 149 * final int[] sorted = ProxySorter.sort( 150 * array, 5, array.length, 151 * (a, i, j) -> Doubler.compare(a[i], a[j]) 152 * ); 153 * for (int i : sorted) { 154 * System.out.println(array[i]); 155 * } 156 * }</pre> 157 * 158 * @since 6.3 159 * 160 * @param array the array which is sorted 161 * @param from the index of the first element (inclusive) to be sorted 162 * @param to the index of the last element (exclusive) to be sorted 163 * @param comparator the array element comparator 164 * @param <T> the array type 165 * @return the sorted index array 166 * @throws NullPointerException if one of the arrays or comparator is 167 * {@code null} 168 * @throws IllegalArgumentException if {@code from > to} 169 * @throws ArrayIndexOutOfBoundsException if {@code from < 0} 170 */ 171 public static <T> int[] sort( 172 final T array, 173 final int from, 174 final int to, 175 final Comparator<? super T> comparator 176 ) { 177 return TimProxySorter.sort(array, from, to, comparator); 178 } 179 180 /** 181 * Sorting the given array by creating an index lookup array. The original 182 * array is not touched, and the returned array can then be used for 183 * iterating the array in ascending order. 184 * 185 * <pre>{@code 186 * final double[] array = ...; 187 * final int[] sorted = ProxySorter.sort( 188 * array, array.length, 189 * (a, i, j) -> Doubler.compare(a[i], a[j]) 190 * ); 191 * for (int i : sorted) { 192 * System.out.println(array[i]); 193 * } 194 * }</pre> 195 * 196 * @param array the array which is sorted 197 * @param length the array length 198 * @param comparator the array element comparator 199 * @param <T> the array type 200 * @return the sorted index array 201 * @throws NullPointerException if one of the arrays is {@code null} 202 * @throws IllegalArgumentException if {@code length < 0} 203 */ 204 public static <T> int[] sort( 205 final T array, 206 final int length, 207 final Comparator<? super T> comparator 208 ) { 209 return sort(array, 0, length, comparator); 210 } 211 212 213 /* ************************************************************************* 214 * Derived sorting methods. 215 * ************************************************************************/ 216 217 /** 218 * Sorting the given array by creating an index lookup array. 219 * 220 * @see #sort(Object, int, Comparator) 221 * 222 * @param array the array to sort 223 * @return the <em>sorted</em> index lookup array 224 * @throws NullPointerException if the array is {@code null} 225 */ 226 public static int[] sort(final int[] array) { 227 return sort(array, array.length, ProxySorter::compare); 228 } 229 230 private static int compare(final int[] a, final int i, final int j) { 231 return Integer.compare(a[i], a[j]); 232 } 233 234 /** 235 * Sorting the given array by creating an index lookup array. 236 * 237 * @see #sort(Object, int, int, Comparator) 238 * 239 * @since 6.3 240 * 241 * @param array the array to sort 242 * @param from the index of the first element (inclusive) to be sorted 243 * @param to the index of the last element (exclusive) to be sorted 244 * @return the <em>sorted</em> index lookup array 245 * @throws IllegalArgumentException if {@code from > to} 246 * @throws IndexOutOfBoundsException if the sub-range is out of bounds 247 */ 248 public static int[] sort(final int[] array, final int from, final int to) { 249 checkFromToIndex(from, to, array.length); 250 return sort(array, from, to, ProxySorter::compare); 251 } 252 253 /** 254 * Sorting the given array by creating an index lookup array. 255 * 256 * @see #sort(Object, int, Comparator) 257 * 258 * @param array the array to sort 259 * @return the <em>sorted</em> index lookup array 260 * @throws NullPointerException if the array is {@code null} 261 */ 262 public static int[] sort(final long[] array) { 263 return sort(array, array.length, ProxySorter::compare); 264 } 265 266 private static int compare(final long[] a, final int i, final int j) { 267 return Long.compare(a[i], a[j]); 268 } 269 270 /** 271 * Sorting the given array by creating an index lookup array. 272 * 273 * @see #sort(Object, int, int, Comparator) 274 * 275 * @since 6.3 276 * 277 * @param array the array to sort 278 * @param from the index of the first element (inclusive) to be sorted 279 * @param to the index of the last element (exclusive) to be sorted 280 * @return the <em>sorted</em> index lookup array 281 * @throws IllegalArgumentException if {@code from > to} 282 * @throws IndexOutOfBoundsException if the sub-range is out of bounds 283 */ 284 public static int[] sort(final long[] array, final int from, final int to) { 285 checkFromToIndex(from, to, array.length); 286 return sort(array, from, to, ProxySorter::compare); 287 } 288 289 /** 290 * Sorting the given array by creating an index lookup array. 291 * 292 * @see #sort(Object, int, Comparator) 293 * 294 * @param array the array to sort 295 * @return the <em>sorted</em> index lookup array 296 * @throws NullPointerException if the array is {@code null} 297 */ 298 public static int[] sort(final double[] array) { 299 return sort(array, array.length, ProxySorter::compare); 300 } 301 302 private static int compare(final double[] a, final int i, final int j) { 303 return Double.compare(a[i], a[j]); 304 } 305 306 /** 307 * Sorting the given array by creating an index lookup array. 308 * 309 * @see #sort(Object, int, int, Comparator) 310 * 311 * @since 6.3 312 * 313 * @param array the array to sort 314 * @param from the index of the first element (inclusive) to be sorted 315 * @param to the index of the last element (exclusive) to be sorted 316 * @return the <em>sorted</em> index lookup array 317 * @throws IllegalArgumentException if {@code from > to} 318 * @throws IndexOutOfBoundsException if the sub-range is out of bounds 319 */ 320 public static int[] sort(final double[] array, final int from, final int to) { 321 checkFromToIndex(from, to, array.length); 322 return sort(array, from, to, ProxySorter::compare); 323 } 324 325 /** 326 * Sorting the given array by creating an index lookup array. 327 * 328 * @see #sort(Object, int, Comparator) 329 * 330 * @param <T> the array element type 331 * @param array the array to sort 332 * @param comparator the array element comparator 333 * @return the <em>sorted</em> index lookup array 334 * @throws NullPointerException if one of the arguments is {@code null} 335 */ 336 public static <T> int[] sort( 337 final T[] array, 338 final java.util.Comparator<? super T> comparator 339 ) { 340 return sort( 341 array, array.length, 342 (a, i, j) -> comparator.compare(a[i], a[j]) 343 ); 344 } 345 346 /** 347 * Sorting the given array by creating an index lookup array. 348 * 349 * @see #sort(Object, int, int, Comparator) 350 * 351 * @since 6.3 352 * 353 * @param <T> the array element type 354 * @param array the array to sort 355 * @param from the index of the first element (inclusive) to be sorted 356 * @param to the index of the last element (exclusive) to be sorted 357 * @param comparator the array element comparator 358 * @return the <em>sorted</em> index lookup array 359 * @throws NullPointerException if one of the arguments is {@code null} 360 * @throws IllegalArgumentException if {@code from > to} 361 * @throws IndexOutOfBoundsException if the sub-range is out of bounds 362 */ 363 public static <T> int[] sort( 364 final T[] array, 365 final int from, 366 final int to, 367 final java.util.Comparator<? super T> comparator 368 ) { 369 checkFromToIndex(from, to, array.length); 370 return sort( 371 array, from, to, 372 (a, i, j) -> comparator.compare(a[i], a[j]) 373 ); 374 } 375 376 /** 377 * Sorting the given array by creating an index lookup array. 378 * 379 * @see #sort(Object, int, Comparator) 380 * 381 * @param <T> the array element type 382 * @param array the array to sort 383 * @return the <em>sorted</em> index lookup array 384 * @throws NullPointerException if the array is {@code null} 385 */ 386 public static <T extends Comparable<? super T>> int[] sort(final T[] array) { 387 return sort( 388 array, array.length, 389 (a, i, j) -> a[i].compareTo(a[j]) 390 ); 391 } 392 393 /** 394 * Sorting the given array by creating an index lookup array. 395 * 396 * @see #sort(Object, int, int, Comparator) 397 * 398 * @since 6.3 399 * 400 * @param <T> the array element type 401 * @param array the array to sort 402 * @param from the index of the first element (inclusive) to be sorted 403 * @param to the index of the last element (exclusive) to be sorted 404 * @return the <em>sorted</em> index lookup array 405 * @throws NullPointerException if the array is {@code null} 406 * @throws IllegalArgumentException if {@code from > to} 407 * @throws IndexOutOfBoundsException if the sub-range is out of bounds 408 */ 409 public static <T extends Comparable<? super T>> int[] sort( 410 final T[] array, 411 final int from, 412 final int to 413 ) { 414 checkFromToIndex(from, to, array.length); 415 return sort( 416 array, from, to, 417 (a, i, j) -> a[i].compareTo(a[j]) 418 ); 419 } 420 421 /** 422 * Sorting the given array by creating an index lookup array. 423 * 424 * @see #sort(Object, int, Comparator) 425 * 426 * @param <T> the array element type 427 * @param array the array to sort 428 * @param comparator the array element comparator 429 * @return the <em>sorted</em> index lookup array 430 * @throws NullPointerException if one of the arguments is {@code null} 431 */ 432 public static <T> int[] sort( 433 final BaseSeq<? extends T> array, 434 final java.util.Comparator<? super T> comparator 435 ) { 436 return sort( 437 array, array.length(), 438 (a, i, j) -> comparator.compare(a.get(i), a.get(j)) 439 ); 440 } 441 442 /** 443 * Sorting the given array by creating an index lookup array. 444 * 445 * @see #sort(Object, int, int, Comparator) 446 * 447 * @since 6.3 448 * 449 * @param <T> the array element type 450 * @param array the array to sort 451 * @param from the index of the first element (inclusive) to be sorted 452 * @param to the index of the last element (exclusive) to be sorted 453 * @param comparator the array element comparator 454 * @return the <em>sorted</em> index lookup array 455 * @throws NullPointerException if one of the arguments is {@code null} 456 * @throws IllegalArgumentException if {@code from > to} 457 * @throws IndexOutOfBoundsException if the sub-range is out of bounds 458 */ 459 public static <T> int[] sort( 460 final BaseSeq<? extends T> array, 461 final int from, 462 final int to, 463 final java.util.Comparator<? super T> comparator 464 ) { 465 checkFromToIndex(from, to, array.length()); 466 return sort( 467 array, from, to, 468 (a, i, j) -> comparator.compare(a.get(i), a.get(j)) 469 ); 470 } 471 472 /** 473 * Sorting the given array by creating an index lookup array. 474 * 475 * @see #sort(Object, int, Comparator) 476 * 477 * @param <T> the array element type 478 * @param array the array to sort 479 * @return the <em>sorted</em> index lookup array 480 * @throws NullPointerException if the array is {@code null} 481 */ 482 public static <T extends Comparable<? super T>> 483 int[] sort(final BaseSeq<? extends T> array) { 484 return sort( 485 array, array.length(), 486 (a, i, j) -> a.get(i).compareTo(a.get(j)) 487 ); 488 } 489 490 /** 491 * Sorting the given array by creating an index lookup array. 492 * 493 * @see #sort(Object, int, int, Comparator) 494 * 495 * @since 6.3 496 * 497 * @param <T> the array element type 498 * @param array the array to sort 499 * @param from the index of the first element (inclusive) to be sorted 500 * @param to the index of the last element (exclusive) to be sorted 501 * @return the <em>sorted</em> index lookup array 502 * @throws NullPointerException if the array is {@code null} 503 * @throws IllegalArgumentException if {@code from > to} 504 * @throws IndexOutOfBoundsException if the sub-range is out of bounds 505 */ 506 public static <T extends Comparable<? super T>> 507 int[] sort(final BaseSeq<? extends T> array, final int from, final int to) { 508 checkFromToIndex(from, to, array.length()); 509 return sort( 510 array, from, to, 511 (a, i, j) -> a.get(i).compareTo(a.get(j)) 512 ); 513 } 514 515 /** 516 * Sorting the given array by creating an index lookup array. 517 * 518 * @see #sort(Object, int, Comparator) 519 * 520 * @param <T> the array element type 521 * @param array the array to sort 522 * @param comparator the array element comparator 523 * @return the <em>sorted</em> index lookup array 524 * @throws NullPointerException if one of the arguments is {@code null} 525 */ 526 public static <T> int[] sort( 527 final List<? extends T> array, 528 final java.util.Comparator<? super T> comparator 529 ) { 530 return sort( 531 array, array.size(), 532 (a, i, j) -> comparator.compare(a.get(i), a.get(j)) 533 ); 534 } 535 536 /** 537 * Sorting the given array by creating an index lookup array. 538 * 539 * @see #sort(Object, int, int, Comparator) 540 * 541 * @since 6.3 542 * 543 * @param <T> the array element type 544 * @param array the array to sort 545 * @param from the index of the first element (inclusive) to be sorted 546 * @param to the index of the last element (exclusive) to be sorted 547 * @param comparator the array element comparator 548 * @return the <em>sorted</em> index lookup array 549 * @throws NullPointerException if one of the arguments is {@code null} 550 * @throws IllegalArgumentException if {@code from > to} 551 * @throws IndexOutOfBoundsException if the sub-range is out of bounds 552 */ 553 public static <T> int[] sort( 554 final List<? extends T> array, 555 final int from, 556 final int to, 557 final java.util.Comparator<? super T> comparator 558 ) { 559 checkFromToIndex(from, to, array.size()); 560 return sort( 561 array, from, to, 562 (a, i, j) -> comparator.compare(a.get(i), a.get(j)) 563 ); 564 } 565 566 /** 567 * Sorting the given array by creating an index lookup array. 568 * 569 * @see #sort(Object, int, Comparator) 570 * 571 * @param <T> the array element type 572 * @param array the array to sort 573 * @return the <em>sorted</em> index lookup array 574 * @throws NullPointerException if the array is {@code null} 575 */ 576 public static <T extends Comparable<? super T>> 577 int[] sort(final List<? extends T> array) { 578 return sort( 579 array, array.size(), 580 (a, i, j) -> a.get(i).compareTo(a.get(j)) 581 ); 582 } 583 584 /** 585 * Sorting the given array by creating an index lookup array. 586 * 587 * @see #sort(Object, int, int, Comparator) 588 * 589 * @since 6.3 590 * 591 * @param <T> the array element type 592 * @param array the array to sort 593 * @param from the index of the first element (inclusive) to be sorted 594 * @param to the index of the last element (exclusive) to be sorted 595 * @return the <em>sorted</em> index lookup array 596 * @throws NullPointerException if the array is {@code null} 597 * @throws IllegalArgumentException if {@code from > to} 598 * @throws IndexOutOfBoundsException if the sub-range is out of bounds 599 */ 600 public static <T extends Comparable<? super T>> 601 int[] sort(final List<? extends T> array, final int from, final int to) { 602 checkFromToIndex(from, to, array.size()); 603 return sort( 604 array, from, to, 605 (a, i, j) -> a.get(i).compareTo(a.get(j)) 606 ); 607 } 608 609 /* ************************************************************************* 610 * Some helper methods. 611 * ************************************************************************/ 612 613 /** 614 * Create an initial indexes array of the given {@code length}. 615 * 616 * @param length the length of the indexes array 617 * @return the initialized indexes array 618 */ 619 static int[] indexes(final int length) { 620 return init(new int[length]); 621 } 622 623 /** 624 * Initializes the given {@code indexes} array. 625 * 626 * @param indexes the index array to initialize 627 * @return the initialized indexes array 628 * @throws NullPointerException if the given {@code indexes} array is 629 * {@code null} 630 */ 631 private static int[] init(final int[] indexes) { 632 for (int i = 0; i < indexes.length; ++i) { 633 indexes[i] = i; 634 } 635 return indexes; 636 } 637 638}