SortInPlace.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.apache.commons.numbers.arrays;

  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.Collections;
  21. import java.util.Comparator;
  22. import java.util.List;

  23. /**
  24.  * Sort an array and perform the same reordering of entries on other arrays.
  25.  * For example, if
  26.  * <ul>
  27.  *  <li>{@code x = [3, 1, 2]}</li>
  28.  *  <li>{@code y = [1, 2, 3]}</li>
  29.  *  <li>{@code z = [0, 5, 7]}</li>
  30.  * </ul>
  31.  * then {@code Sort.ASCENDING.apply(x, y, z)} will update those arrays:
  32.  * <ul>
  33.  *  <li>{@code x = [1, 2, 3]}</li>
  34.  *  <li>{@code y = [2, 3, 1]}</li>
  35.  *  <li>{@code z = [5, 7, 0]}</li>
  36.  * </ul>
  37.  */
  38. public enum SortInPlace {
  39.     /** Sort in ascending order. */
  40.     ASCENDING((o1, o2) -> Double.compare(o1.key(), o2.key())),
  41.     /** Sort in descending order. */
  42.     DESCENDING((o1, o2) -> Double.compare(o2.key(), o1.key()));

  43.     /** Comparator. */
  44.     private final Comparator<PairDoubleInteger> comparator;

  45.     /**
  46.      * @param comparator Comparator.
  47.      */
  48.     SortInPlace(Comparator<PairDoubleInteger> comparator) {
  49.         this.comparator = comparator;
  50.     }

  51.     /**
  52.      * Sorts in place.
  53.      *
  54.      * @param x Array to be sorted and used as a pattern for permutation of
  55.      * the other arrays.
  56.      * @param yList Set of arrays whose permutations of entries will follow
  57.      * those performed on {@code x}.
  58.      * @throws IllegalArgumentException if not all arrays have the same size.
  59.      */
  60.     public void apply(double[] x,
  61.                       double[]... yList) {
  62.         final int yListLen = yList.length;
  63.         final int len = x.length;

  64.         for (int j = 0; j < yListLen; j++) {
  65.             final double[] y = yList[j];
  66.             if (y.length != len) {
  67.                 throw new IllegalArgumentException("Size mismatch: " +
  68.                                                    y.length + " != " + len);
  69.             }
  70.         }

  71.         // Associate each abscissa "x[i]" with its index "i".
  72.         final List<PairDoubleInteger> list = new ArrayList<>(len);
  73.         for (int i = 0; i < len; i++) {
  74.             list.add(new PairDoubleInteger(x[i], i));
  75.         }

  76.         // Sort.
  77.         Collections.sort(list, comparator);

  78.         // Modify the original array so that its elements are in the prescribed order.
  79.         // Retrieve indices of original locations.
  80.         final int[] indices = new int[len];
  81.         for (int i = 0; i < len; i++) {
  82.             final PairDoubleInteger e = list.get(i);
  83.             x[i] = e.key();
  84.             indices[i] = e.value();
  85.         }

  86.         // In every associated array, move the elements to their new location.
  87.         for (int j = 0; j < yListLen; j++) {
  88.             // Input array will be modified in place.
  89.             final double[] yInPlace = yList[j];
  90.             final double[] yOrig = Arrays.copyOf(yInPlace, len);

  91.             for (int i = 0; i < len; i++) {
  92.                 yInPlace[i] = yOrig[indices[i]];
  93.             }
  94.         }
  95.     }

  96.     /**
  97.      * Helper data structure holding a (double, integer) pair.
  98.      */
  99.     private static class PairDoubleInteger {
  100.         /** Key. */
  101.         private final double key;
  102.         /** Value. */
  103.         private final int value;

  104.         /**
  105.          * @param key Key.
  106.          * @param value Value.
  107.          */
  108.         PairDoubleInteger(double key,
  109.                           int value) {
  110.             this.key = key;
  111.             this.value = value;
  112.         }

  113.         /** @return the key. */
  114.         double key() {
  115.             return key;
  116.         }

  117.         /** @return the value. */
  118.         int value() {
  119.             return value;
  120.         }
  121.     }
  122. }