diff --git a/android/guava-tests/test/com/google/common/math/QuantilesTest.java b/android/guava-tests/test/com/google/common/math/QuantilesTest.java index b6e5fc1652cb..5ac5f6e303e6 100644 --- a/android/guava-tests/test/com/google/common/math/QuantilesTest.java +++ b/android/guava-tests/test/com/google/common/math/QuantilesTest.java @@ -290,6 +290,18 @@ public void testScale_indexes_varargs_compute_integerCollection() { 8, SIXTEEN_SQUARES_DECILE_8); } + public void testScale_indexes_varargs_compute_indexOrderIsMaintained() { + assertThat(Quantiles.scale(10).indexes(0, 10, 5, 1, 8, 1).compute(SIXTEEN_SQUARES_INTEGERS)) + .comparingValuesUsing(QUANTILE_CORRESPONDENCE) + .containsExactly( + 0, SIXTEEN_SQUARES_MIN, + 10, SIXTEEN_SQUARES_MAX, + 5, SIXTEEN_SQUARES_MEDIAN, + 1, SIXTEEN_SQUARES_DECILE_1, + 8, SIXTEEN_SQUARES_DECILE_8) + .inOrder(); + } + public void testScale_indexes_varargs_compute_doubleVarargs() { double[] dataset = Doubles.toArray(SIXTEEN_SQUARES_DOUBLES); assertThat(Quantiles.scale(10).indexes(0, 10, 5, 1, 8, 1).compute(dataset)) diff --git a/android/guava/src/com/google/common/math/Quantiles.java b/android/guava/src/com/google/common/math/Quantiles.java index f179c5b85b7a..7aac58f077ea 100644 --- a/android/guava/src/com/google/common/math/Quantiles.java +++ b/android/guava/src/com/google/common/math/Quantiles.java @@ -27,7 +27,7 @@ import com.google.common.primitives.Ints; import java.math.RoundingMode; import java.util.Collection; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; /** @@ -331,8 +331,10 @@ private ScaleAndIndexes(int scale, int[] indexes) { * @param dataset the dataset to do the calculation on, which must be non-empty, which will be * cast to doubles (with any associated lost of precision), and which will not be mutated by * this call (it is copied instead) - * @return an unmodifiable map of results: the keys will be the specified quantile indexes, and - * the values the corresponding quantile values + * @return an unmodifiable, ordered map of results: the keys will be the specified quantile + * indexes, and the values the corresponding quantile values. When iterating, entries in the + * map are ordered by quantile index in the same order they were passed to the {@code + * indexes} method. */ public Map compute(Collection dataset) { return computeInPlace(Doubles.toArray(dataset)); @@ -343,8 +345,10 @@ public Map compute(Collection dataset) { * * @param dataset the dataset to do the calculation on, which must be non-empty, which will not * be mutated by this call (it is copied instead) - * @return an unmodifiable map of results: the keys will be the specified quantile indexes, and - * the values the corresponding quantile values + * @return an unmodifiable, ordered map of results: the keys will be the specified quantile + * indexes, and the values the corresponding quantile values. When iterating, entries in the + * map are ordered by quantile index in the same order they were passed to the {@code + * indexes} method. */ public Map compute(double... dataset) { return computeInPlace(dataset.clone()); @@ -356,8 +360,10 @@ public Map compute(double... dataset) { * @param dataset the dataset to do the calculation on, which must be non-empty, which will be * cast to doubles (with any associated lost of precision), and which will not be mutated by * this call (it is copied instead) - * @return an unmodifiable map of results: the keys will be the specified quantile indexes, and - * the values the corresponding quantile values + * @return an unmodifiable, ordered map of results: the keys will be the specified quantile + * indexes, and the values the corresponding quantile values. When iterating, entries in the + * map are ordered by quantile index in the same order they were passed to the {@code + * indexes} method. */ public Map compute(long... dataset) { return computeInPlace(longsToDoubles(dataset)); @@ -368,8 +374,10 @@ public Map compute(long... dataset) { * * @param dataset the dataset to do the calculation on, which must be non-empty, which will be * cast to doubles, and which will not be mutated by this call (it is copied instead) - * @return an unmodifiable map of results: the keys will be the specified quantile indexes, and - * the values the corresponding quantile values + * @return an unmodifiable, ordered map of results: the keys will be the specified quantile + * indexes, and the values the corresponding quantile values. When iterating, entries in the + * map are ordered by quantile index in the same order they were passed to the {@code + * indexes} method. */ public Map compute(int... dataset) { return computeInPlace(intsToDoubles(dataset)); @@ -380,13 +388,15 @@ public Map compute(int... dataset) { * * @param dataset the dataset to do the calculation on, which must be non-empty, and which will * be arbitrarily reordered by this method call - * @return an unmodifiable map of results: the keys will be the specified quantile indexes, and - * the values the corresponding quantile values + * @return an unmodifiable, ordered map of results: the keys will be the specified quantile + * indexes, and the values the corresponding quantile values. When iterating, entries in the + * map are ordered by quantile index in the same order that the indexes were passed to the + * {@code indexes} method. */ public Map computeInPlace(double... dataset) { checkArgument(dataset.length > 0, "Cannot calculate quantiles of an empty dataset"); if (containsNaN(dataset)) { - Map nanMap = new HashMap<>(); + Map nanMap = new LinkedHashMap<>(); for (int index : indexes) { nanMap.put(index, NaN); } @@ -425,7 +435,7 @@ public Map computeInPlace(double... dataset) { sort(requiredSelections, 0, requiredSelectionsCount); selectAllInPlace( requiredSelections, 0, requiredSelectionsCount - 1, dataset, 0, dataset.length - 1); - Map ret = new HashMap<>(); + Map ret = new LinkedHashMap<>(); for (int i = 0; i < indexes.length; i++) { int quotient = quotients[i]; int remainder = remainders[i]; diff --git a/guava-tests/test/com/google/common/math/QuantilesTest.java b/guava-tests/test/com/google/common/math/QuantilesTest.java index bca83028383f..a9b7872994cb 100644 --- a/guava-tests/test/com/google/common/math/QuantilesTest.java +++ b/guava-tests/test/com/google/common/math/QuantilesTest.java @@ -290,6 +290,18 @@ public void testScale_indexes_varargs_compute_integerCollection() { 8, SIXTEEN_SQUARES_DECILE_8); } + public void testScale_indexes_varargs_compute_indexOrderIsMaintained() { + assertThat(Quantiles.scale(10).indexes(0, 10, 5, 1, 8, 1).compute(SIXTEEN_SQUARES_INTEGERS)) + .comparingValuesUsing(QUANTILE_CORRESPONDENCE) + .containsExactly( + 0, SIXTEEN_SQUARES_MIN, + 10, SIXTEEN_SQUARES_MAX, + 5, SIXTEEN_SQUARES_MEDIAN, + 1, SIXTEEN_SQUARES_DECILE_1, + 8, SIXTEEN_SQUARES_DECILE_8) + .inOrder(); + } + public void testScale_indexes_varargs_compute_doubleVarargs() { double[] dataset = Doubles.toArray(SIXTEEN_SQUARES_DOUBLES); assertThat(Quantiles.scale(10).indexes(0, 10, 5, 1, 8, 1).compute(dataset)) diff --git a/guava/src/com/google/common/math/Quantiles.java b/guava/src/com/google/common/math/Quantiles.java index f179c5b85b7a..7aac58f077ea 100644 --- a/guava/src/com/google/common/math/Quantiles.java +++ b/guava/src/com/google/common/math/Quantiles.java @@ -27,7 +27,7 @@ import com.google.common.primitives.Ints; import java.math.RoundingMode; import java.util.Collection; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; /** @@ -331,8 +331,10 @@ private ScaleAndIndexes(int scale, int[] indexes) { * @param dataset the dataset to do the calculation on, which must be non-empty, which will be * cast to doubles (with any associated lost of precision), and which will not be mutated by * this call (it is copied instead) - * @return an unmodifiable map of results: the keys will be the specified quantile indexes, and - * the values the corresponding quantile values + * @return an unmodifiable, ordered map of results: the keys will be the specified quantile + * indexes, and the values the corresponding quantile values. When iterating, entries in the + * map are ordered by quantile index in the same order they were passed to the {@code + * indexes} method. */ public Map compute(Collection dataset) { return computeInPlace(Doubles.toArray(dataset)); @@ -343,8 +345,10 @@ public Map compute(Collection dataset) { * * @param dataset the dataset to do the calculation on, which must be non-empty, which will not * be mutated by this call (it is copied instead) - * @return an unmodifiable map of results: the keys will be the specified quantile indexes, and - * the values the corresponding quantile values + * @return an unmodifiable, ordered map of results: the keys will be the specified quantile + * indexes, and the values the corresponding quantile values. When iterating, entries in the + * map are ordered by quantile index in the same order they were passed to the {@code + * indexes} method. */ public Map compute(double... dataset) { return computeInPlace(dataset.clone()); @@ -356,8 +360,10 @@ public Map compute(double... dataset) { * @param dataset the dataset to do the calculation on, which must be non-empty, which will be * cast to doubles (with any associated lost of precision), and which will not be mutated by * this call (it is copied instead) - * @return an unmodifiable map of results: the keys will be the specified quantile indexes, and - * the values the corresponding quantile values + * @return an unmodifiable, ordered map of results: the keys will be the specified quantile + * indexes, and the values the corresponding quantile values. When iterating, entries in the + * map are ordered by quantile index in the same order they were passed to the {@code + * indexes} method. */ public Map compute(long... dataset) { return computeInPlace(longsToDoubles(dataset)); @@ -368,8 +374,10 @@ public Map compute(long... dataset) { * * @param dataset the dataset to do the calculation on, which must be non-empty, which will be * cast to doubles, and which will not be mutated by this call (it is copied instead) - * @return an unmodifiable map of results: the keys will be the specified quantile indexes, and - * the values the corresponding quantile values + * @return an unmodifiable, ordered map of results: the keys will be the specified quantile + * indexes, and the values the corresponding quantile values. When iterating, entries in the + * map are ordered by quantile index in the same order they were passed to the {@code + * indexes} method. */ public Map compute(int... dataset) { return computeInPlace(intsToDoubles(dataset)); @@ -380,13 +388,15 @@ public Map compute(int... dataset) { * * @param dataset the dataset to do the calculation on, which must be non-empty, and which will * be arbitrarily reordered by this method call - * @return an unmodifiable map of results: the keys will be the specified quantile indexes, and - * the values the corresponding quantile values + * @return an unmodifiable, ordered map of results: the keys will be the specified quantile + * indexes, and the values the corresponding quantile values. When iterating, entries in the + * map are ordered by quantile index in the same order that the indexes were passed to the + * {@code indexes} method. */ public Map computeInPlace(double... dataset) { checkArgument(dataset.length > 0, "Cannot calculate quantiles of an empty dataset"); if (containsNaN(dataset)) { - Map nanMap = new HashMap<>(); + Map nanMap = new LinkedHashMap<>(); for (int index : indexes) { nanMap.put(index, NaN); } @@ -425,7 +435,7 @@ public Map computeInPlace(double... dataset) { sort(requiredSelections, 0, requiredSelectionsCount); selectAllInPlace( requiredSelections, 0, requiredSelectionsCount - 1, dataset, 0, dataset.length - 1); - Map ret = new HashMap<>(); + Map ret = new LinkedHashMap<>(); for (int i = 0; i < indexes.length; i++) { int quotient = quotients[i]; int remainder = remainders[i];