View Javadoc
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  
18  package org.apache.commons.numbers.arrays;
19  
20  import java.util.ArrayList;
21  import java.util.Arrays;
22  import java.util.Collections;
23  import java.util.Comparator;
24  import java.util.List;
25  
26  /**
27   * Sort an array and perform the same reordering of entries on other arrays.
28   * For example, if
29   * <ul>
30   *  <li>{@code x = [3, 1, 2]}</li>
31   *  <li>{@code y = [1, 2, 3]}</li>
32   *  <li>{@code z = [0, 5, 7]}</li>
33   * </ul>
34   * then {@code Sort.ASCENDING.apply(x, y, z)} will update those arrays:
35   * <ul>
36   *  <li>{@code x = [1, 2, 3]}</li>
37   *  <li>{@code y = [2, 3, 1]}</li>
38   *  <li>{@code z = [5, 7, 0]}</li>
39   * </ul>
40   */
41  public enum SortInPlace {
42      /** Sort in ascending order. */
43      ASCENDING((o1, o2) -> Double.compare(o1.key(), o2.key())),
44      /** Sort in descending order. */
45      DESCENDING((o1, o2) -> Double.compare(o2.key(), o1.key()));
46  
47      /** Comparator. */
48      private final Comparator<PairDoubleInteger> comparator;
49  
50      /**
51       * @param comparator Comparator.
52       */
53      SortInPlace(Comparator<PairDoubleInteger> comparator) {
54          this.comparator = comparator;
55      }
56  
57      /**
58       * Sorts in place.
59       *
60       * @param x Array to be sorted and used as a pattern for permutation of
61       * the other arrays.
62       * @param yList Set of arrays whose permutations of entries will follow
63       * those performed on {@code x}.
64       * @throws IllegalArgumentException if not all arrays have the same size.
65       */
66      public void apply(double[] x,
67                        double[]... yList) {
68          final int yListLen = yList.length;
69          final int len = x.length;
70  
71          for (int j = 0; j < yListLen; j++) {
72              final double[] y = yList[j];
73              if (y.length != len) {
74                  throw new IllegalArgumentException("Size mismatch: " +
75                                                     y.length + " != " + len);
76              }
77          }
78  
79          // Associate each abscissa "x[i]" with its index "i".
80          final List<PairDoubleInteger> list = new ArrayList<>(len);
81          for (int i = 0; i < len; i++) {
82              list.add(new PairDoubleInteger(x[i], i));
83          }
84  
85          // Sort.
86          Collections.sort(list, comparator);
87  
88          // Modify the original array so that its elements are in the prescribed order.
89          // Retrieve indices of original locations.
90          final int[] indices = new int[len];
91          for (int i = 0; i < len; i++) {
92              final PairDoubleInteger e = list.get(i);
93              x[i] = e.key();
94              indices[i] = e.value();
95          }
96  
97          // In every associated array, move the elements to their new location.
98          for (int j = 0; j < yListLen; j++) {
99              // Input array will be modified in place.
100             final double[] yInPlace = yList[j];
101             final double[] yOrig = Arrays.copyOf(yInPlace, len);
102 
103             for (int i = 0; i < len; i++) {
104                 yInPlace[i] = yOrig[indices[i]];
105             }
106         }
107     }
108 
109     /**
110      * Helper data structure holding a (double, integer) pair.
111      */
112     private static class PairDoubleInteger {
113         /** Key. */
114         private final double key;
115         /** Value. */
116         private final int value;
117 
118         /**
119          * @param key Key.
120          * @param value Value.
121          */
122         PairDoubleInteger(double key,
123                           int value) {
124             this.key = key;
125             this.value = value;
126         }
127 
128         /** @return the key. */
129         double key() {
130             return key;
131         }
132 
133         /** @return the value. */
134         int value() {
135             return value;
136         }
137     }
138 }