diff --git a/src/main/java/org/apache/commons/lang3/ArrayUtils.java b/src/main/java/org/apache/commons/lang3/ArrayUtils.java index 4b6b2cf0b5a..3a7dafb80f9 100644 --- a/src/main/java/org/apache/commons/lang3/ArrayUtils.java +++ b/src/main/java/org/apache/commons/lang3/ArrayUtils.java @@ -4265,6 +4265,9 @@ public static int lastIndexOf(final double[] array, final double valueToFind, fi * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input. */ public static int lastIndexOf(final double[] array, final double valueToFind, int startIndex) { + if (Double.isNaN(valueToFind)) { + return lastIndexOfNaN(array, startIndex); + } if (isEmpty(array) || startIndex < 0) { return INDEX_NOT_FOUND; } @@ -4296,6 +4299,9 @@ public static int lastIndexOf(final double[] array, final double valueToFind, in * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input. */ public static int lastIndexOf(final double[] array, final double valueToFind, int startIndex, final double tolerance) { + if (Double.isNaN(valueToFind)) { + return lastIndexOfNaN(array, startIndex); + } if (isEmpty(array) || startIndex < 0) { return INDEX_NOT_FOUND; } @@ -4347,8 +4353,10 @@ public static int lastIndexOf(final float[] array, final float valueToFind, int if (startIndex >= array.length) { startIndex = array.length - 1; } + final boolean searchNaN = Float.isNaN(valueToFind); for (int i = startIndex; i >= 0; i--) { - if (valueToFind == array[i]) { + final float element = array[i]; + if (valueToFind == element || searchNaN && Float.isNaN(element)) { return i; } } @@ -4535,6 +4543,24 @@ public static int lastIndexOf(final short[] array, final short valueToFind, int return INDEX_NOT_FOUND; } + /** + * Finds the last index of the NaN value in a double array. + * @param array the array to traverse backwards for NaN, may be {@code null}. + * @param startIndex the start index to traverse backwards from. + * @return the last index of the NaN value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input. + */ + private static int lastIndexOfNaN(final double[] array, final int startIndex) { + if (isEmpty(array) || startIndex < 0) { + return INDEX_NOT_FOUND; + } + for (int i = Math.min(startIndex, array.length - 1); i >= 0; i--) { + if (Double.isNaN(array[i])) { + return i; + } + } + return INDEX_NOT_FOUND; + } + /** * Maps elements from an array into elements of a new array of a given type, while mapping old elements to new elements. * diff --git a/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java b/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java index a096e949fff..b9faef8c4e0 100644 --- a/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java @@ -1824,6 +1824,27 @@ void testLastIndexOfDouble() { assertEquals(-1, ArrayUtils.lastIndexOf(array, 99)); } + @Test + void testLastIndexOfDoubleNaN() { + final double[] array = { Double.NaN, Double.NEGATIVE_INFINITY, Double.NaN, Double.POSITIVE_INFINITY }; + assertEquals(2, ArrayUtils.lastIndexOf(array, Double.NaN)); + assertEquals(2, ArrayUtils.lastIndexOf(array, Double.NaN, (double) 0)); + assertEquals(0, ArrayUtils.lastIndexOf(array, Double.NaN, 1)); + assertEquals(0, ArrayUtils.lastIndexOf(array, Double.NaN, 1, (double) 0)); + assertEquals(-1, ArrayUtils.lastIndexOf(array, Double.NaN, -1)); + } + + @Test + void testLastIndexOfDoubleInfinity() { + final double[] array = { Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY }; + assertEquals(2, ArrayUtils.lastIndexOf(array, Double.POSITIVE_INFINITY)); + assertEquals(3, ArrayUtils.lastIndexOf(array, Double.NEGATIVE_INFINITY)); + assertEquals(0, ArrayUtils.lastIndexOf(array, Double.POSITIVE_INFINITY, 1)); + assertEquals(1, ArrayUtils.lastIndexOf(array, Double.NEGATIVE_INFINITY, 2)); + assertEquals(2, ArrayUtils.lastIndexOf(array, Double.POSITIVE_INFINITY, array.length, (double) 0)); + assertEquals(1, ArrayUtils.lastIndexOf(array, Double.NEGATIVE_INFINITY, 2, (double) 0)); + } + @Test void testLastIndexOfDoubleTolerance() { double[] array = null; @@ -1884,6 +1905,23 @@ void testLastIndexOfFloat() { assertEquals(-1, ArrayUtils.lastIndexOf(array, 99)); } + @Test + void testLastIndexOfFloatNaN() { + final float[] array = { Float.NaN, Float.NEGATIVE_INFINITY, Float.NaN, Float.POSITIVE_INFINITY }; + assertEquals(2, ArrayUtils.lastIndexOf(array, Float.NaN)); + assertEquals(0, ArrayUtils.lastIndexOf(array, Float.NaN, 1)); + assertEquals(-1, ArrayUtils.lastIndexOf(array, Float.NaN, -1)); + } + + @Test + void testLastIndexOfFloatInfinity() { + final float[] array = { Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY }; + assertEquals(2, ArrayUtils.lastIndexOf(array, Float.POSITIVE_INFINITY)); + assertEquals(3, ArrayUtils.lastIndexOf(array, Float.NEGATIVE_INFINITY)); + assertEquals(0, ArrayUtils.lastIndexOf(array, Float.POSITIVE_INFINITY, 1)); + assertEquals(1, ArrayUtils.lastIndexOf(array, Float.NEGATIVE_INFINITY, 2)); + } + @Test void testLastIndexOfFloatWithStartIndex() { float[] array = null;