From ef26a667633275fa656b74b841f9e74a3a6879ab Mon Sep 17 00:00:00 2001 From: Duncan Jones Date: Sun, 19 Oct 2014 05:52:37 +0000 Subject: [PATCH] LANG-536 - Add isSorted() to ArrayUtils. Patch supplied by James Sawle. Closes #32 in GitHub. git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@1632874 13f79535-47bb-0310-9956-ffa450edef68 --- pom.xml | 3 + src/changes/changes.xml | 1 + .../org/apache/commons/lang3/ArrayUtils.java | 255 +++++++++++++++++- .../apache/commons/lang3/BooleanUtils.java | 21 ++ .../org/apache/commons/lang3/CharUtils.java | 15 +- .../commons/lang3/math/NumberUtils.java | 76 ++++++ .../apache/commons/lang3/ArrayUtilsTest.java | 172 +++++++++++- .../commons/lang3/BooleanUtilsTest.java | 8 + .../apache/commons/lang3/CharUtilsTest.java | 8 +- .../commons/lang3/math/NumberUtilsTest.java | 27 ++ 10 files changed, 574 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index a5da63e28..47f522c62 100644 --- a/pom.xml +++ b/pom.xml @@ -373,6 +373,9 @@ Scott Sanders + + James Sawle + Ralph Schaer diff --git a/src/changes/changes.xml b/src/changes/changes.xml index d2932ce1e..2ddb50e8e 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -22,6 +22,7 @@ + Add isSorted() to ArrayUtils Fix MethodUtilsTest so it does not depend on JDK method ordering CompareToBuilder's doc doesn't specify precedence of fields it uses in performing comparisons ParseException when trying to parse UTC dates with Z as zone designator using DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT diff --git a/src/main/java/org/apache/commons/lang3/ArrayUtils.java b/src/main/java/org/apache/commons/lang3/ArrayUtils.java index 06fb2742b..644c0b880 100644 --- a/src/main/java/org/apache/commons/lang3/ArrayUtils.java +++ b/src/main/java/org/apache/commons/lang3/ArrayUtils.java @@ -19,6 +19,7 @@ import java.lang.reflect.Array; import java.util.Arrays; import java.util.BitSet; +import java.util.Comparator; import java.util.HashMap; import java.util.Map; @@ -26,6 +27,7 @@ import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.commons.lang3.math.NumberUtils; import org.apache.commons.lang3.mutable.MutableInt; /** @@ -5356,7 +5358,7 @@ public static byte[] removeElements(final byte[] array, final byte... values) { if (isEmpty(array) || isEmpty(values)) { return clone(array); } - final HashMap occurrences = new HashMap(values.length); + final Map occurrences = new HashMap(values.length); for (final byte v : values) { final Byte boxed = Byte.valueOf(v); final MutableInt count = occurrences.get(boxed); @@ -6087,4 +6089,255 @@ static Object removeAll(final Object array, final BitSet indices) { } return result; } + + /** + *

This method checks whether the provided array is sorted according to the class's + * {@code compareTo} method.

+ * + * @param array the array to check + * @param the datatype of the array to check, it must implement {@code Comparable} + * @return whether the array is sorted + * @since 3.4 + */ + public static > boolean isSorted(final T[] array) { + return isSorted(array, new Comparator() { + @Override + public int compare(T o1, T o2) { + return o1.compareTo(o2); + } + }); + } + + + /** + *

This method checks whether the provided array is sorted according to the provided {@code Comparator}.

+ * + * @param array the array to check + * @param comparator the {@code Comparator} to compare over + * @param the datatype of the array + * @return whether the array is sorted + * @since 3.4 + */ + public static boolean isSorted(final T[] array, final Comparator comparator) { + if (comparator == null) { + throw new IllegalArgumentException("Comparator should not be null."); + } + + if(array == null || array.length < 2) { + return true; + } + + T previous = array[0]; + final int n = array.length; + for(int i = 1; i < n; i++) { + final T current = array[i]; + if (comparator.compare(previous, current) > 0) { + return false; + } + + previous = current; + } + return true; + } + + /** + *

This method checks whether the provided array is sorted according to natural ordering.

+ * + * @param array the array to check + * @return whether the array is sorted according to natural ordering + * @since 3.4 + */ + public static boolean isSorted(int[] array) { + if(array == null || array.length < 2) { + return true; + } + + int previous = array[0]; + final int n = array.length; + for(int i = 1; i < n; i++) { + final int current = array[i]; + if(NumberUtils.compare(previous, current) > 0) { + return false; + } + + previous = current; + } + return true; + } + + /** + *

This method checks whether the provided array is sorted according to natural ordering.

+ * + * @param array the array to check + * @return whether the array is sorted according to natural ordering + * @since 3.4 + */ + public static boolean isSorted(long[] array) { + if(array == null || array.length < 2) { + return true; + } + + long previous = array[0]; + final int n = array.length; + for(int i = 1; i < n; i++) { + final long current = array[i]; + if(NumberUtils.compare(previous, current) > 0) { + return false; + } + + previous = current; + } + return true; + } + + /** + *

This method checks whether the provided array is sorted according to natural ordering.

+ * + * @param array the array to check + * @return whether the array is sorted according to natural ordering + * @since 3.4 + */ + public static boolean isSorted(short[] array) { + if(array == null || array.length < 2) { + return true; + } + + short previous = array[0]; + final int n = array.length; + for(int i = 1; i < n; i++) { + final short current = array[i]; + if(NumberUtils.compare(previous, current) > 0) { + return false; + } + + previous = current; + } + return true; + } + + /** + *

This method checks whether the provided array is sorted according to natural ordering.

+ * + * @param array the array to check + * @return whether the array is sorted according to natural ordering + * @since 3.4 + */ + public static boolean isSorted(final double[] array) { + if(array == null || array.length < 2) { + return true; + } + + double previous = array[0]; + final int n = array.length; + for(int i = 1; i < n; i++) { + final double current = array[i]; + if(Double.compare(previous, current) > 0) { + return false; + } + + previous = current; + } + return true; + } + + /** + *

This method checks whether the provided array is sorted according to natural ordering.

+ * + * @param array the array to check + * @return whether the array is sorted according to natural ordering + * @since 3.4 + */ + public static boolean isSorted(final float[] array) { + if(array == null || array.length < 2) { + return true; + } + + float previous = array[0]; + final int n = array.length; + for(int i = 1; i < n; i++) { + final float current = array[i]; + if(Float.compare(previous, current) > 0) { + return false; + } + + previous = current; + } + return true; + } + + /** + *

This method checks whether the provided array is sorted according to natural ordering.

+ * + * @param array the array to check + * @return whether the array is sorted according to natural ordering + * @since 3.4 + */ + public static boolean isSorted(byte[] array) { + if(array == null || array.length < 2) { + return true; + } + + byte previous = array[0]; + final int n = array.length; + for(int i = 1; i < n; i++) { + final byte current = array[i]; + if(NumberUtils.compare(previous, current) > 0) { + return false; + } + + previous = current; + } + return true; + } + + /** + *

This method checks whether the provided array is sorted according to natural ordering.

+ * + * @param array the array to check + * @return whether the array is sorted according to natural ordering + * @since 3.4 + */ + public static boolean isSorted(char[] array) { + if(array == null || array.length < 2) { + return true; + } + + char previous = array[0]; + final int n = array.length; + for(int i = 1; i < n; i++) { + final char current = array[i]; + if(CharUtils.compare(previous, current) > 0) { + return false; + } + + previous = current; + } + return true; + } + + /** + *

This method checks whether the provided array is sorted according to natural ordering + * ({@code false} before {@code true}).

+ * + * @param array the array to check + * @return whether the array is sorted according to natural ordering + * @since 3.4 + */ + public static boolean isSorted(boolean[] array) { + if(array == null || array.length < 2) { + return true; + } + + boolean previous = array[0]; + final int n = array.length; + for(int i = 1; i < n; i++) { + final boolean current = array[i]; + if(BooleanUtils.compare(previous, current) > 0) { + return false; + } + + previous = current; + } + return true; + } } diff --git a/src/main/java/org/apache/commons/lang3/BooleanUtils.java b/src/main/java/org/apache/commons/lang3/BooleanUtils.java index fcbad6648..1832fe0fd 100644 --- a/src/main/java/org/apache/commons/lang3/BooleanUtils.java +++ b/src/main/java/org/apache/commons/lang3/BooleanUtils.java @@ -1085,4 +1085,25 @@ public static Boolean xor(final Boolean... array) { } } + /** + *

Compares two {@code boolean} values. This is the same functionality as provided in Java 7.

+ * + * @param x the first {@code boolean} to compare + * @param y the second {@code boolean} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code !x && y}; and + * a value greater than {@code 0} if {@code x && !y} + * @since 3.4 + */ + public static int compare(boolean x, boolean y) { + if (x == y) { + return 0; + } + if (x) { + return 1; + } else { + return -1; + } + } + } diff --git a/src/main/java/org/apache/commons/lang3/CharUtils.java b/src/main/java/org/apache/commons/lang3/CharUtils.java index f8f284e65..3f19a214e 100644 --- a/src/main/java/org/apache/commons/lang3/CharUtils.java +++ b/src/main/java/org/apache/commons/lang3/CharUtils.java @@ -535,5 +535,18 @@ public static boolean isAsciiNumeric(final char ch) { public static boolean isAsciiAlphanumeric(final char ch) { return isAsciiAlpha(ch) || isAsciiNumeric(ch); } - + + /** + *

Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.

+ * + * @param x the first {@code char} to compare + * @param y the second {@code char} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 3.4 + */ + public static int compare(char x, char y) { + return x-y; + } } diff --git a/src/main/java/org/apache/commons/lang3/math/NumberUtils.java b/src/main/java/org/apache/commons/lang3/math/NumberUtils.java index 9eaf57d68..14f4bf469 100644 --- a/src/main/java/org/apache/commons/lang3/math/NumberUtils.java +++ b/src/main/java/org/apache/commons/lang3/math/NumberUtils.java @@ -1495,4 +1495,80 @@ public static boolean isParsable(final String str) { } } + /** + *

Compares two {@code int} values numerically. This is the same functionality as provided in Java 7.

+ * + * @param x the first {@code int} to compare + * @param y the second {@code int} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 3.4 + */ + public static int compare(int x, int y) { + if (x == y) { + return 0; + } + if (x < y) { + return -1; + } else { + return 1; + } + } + + /** + *

Compares to {@code long} values numerically. This is the same functionality as provided in Java 7.

+ * + * @param x the first {@code long} to compare + * @param y the second {@code long} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 3.4 + */ + public static int compare(long x, long y) { + if (x == y) { + return 0; + } + if (x < y) { + return -1; + } else { + return 1; + } + } + + /** + *

Compares to {@code short} values numerically. This is the same functionality as provided in Java 7.

+ * + * @param x the first {@code short} to compare + * @param y the second {@code short} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 3.4 + */ + public static int compare(short x, short y) { + if (x == y) { + return 0; + } + if (x < y) { + return -1; + } else { + return 1; + } + } + + /** + *

Compares two {@code byte} values numerically. This is the same functionality as provided in Java 7.

+ * + * @param x the first {@code byte} to compare + * @param y the second {@code byte} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 3.4 + */ + public static int compare(byte x, byte y) { + return x-y; + } } diff --git a/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java b/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java index af7ceba43..27150aea3 100644 --- a/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java @@ -16,19 +16,12 @@ */ package org.apache.commons.lang3; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; import java.util.Arrays; +import java.util.Comparator; import java.util.Date; import java.util.Map; @@ -3472,4 +3465,165 @@ public void testGetLength() { } catch (final IllegalArgumentException e) {} } + @Test + public void testIsSorted() { + Integer[] array = null; + assertTrue(ArrayUtils.isSorted(array)); + + array = new Integer[]{1}; + assertTrue(ArrayUtils.isSorted(array)); + + array = new Integer[]{1,2,3}; + assertTrue(ArrayUtils.isSorted(array)); + + array = new Integer[]{1,3,2}; + assertFalse(ArrayUtils.isSorted(array)); + } + + @Test + public void testIsSortedComparator() { + Comparator c = new Comparator() { + public int compare(Integer o1, Integer o2) { + return o2.compareTo(o1); + } + }; + + Integer[] array = null; + assertTrue(ArrayUtils.isSorted(array, c)); + + array = new Integer[]{1}; + assertTrue(ArrayUtils.isSorted(array, c)); + + array = new Integer[]{3,2,1}; + assertTrue(ArrayUtils.isSorted(array, c)); + + array = new Integer[]{1,3,2}; + assertFalse(ArrayUtils.isSorted(array, c)); + } + + @Test(expected = IllegalArgumentException.class) + public void testIsSortedNullComparator() throws Exception { + ArrayUtils.isSorted(null, null); + } + + @Test + public void testIsSortedInt() { + int[] array = null; + assertTrue(ArrayUtils.isSorted(array)); + + array = new int[]{1}; + assertTrue(ArrayUtils.isSorted(array)); + + array = new int[]{1,2,3}; + assertTrue(ArrayUtils.isSorted(array)); + + array = new int[]{1,3,2}; + assertFalse(ArrayUtils.isSorted(array)); + } + + @Test + public void testIsSortedFloat() { + float[] array = null; + assertTrue(ArrayUtils.isSorted(array)); + + array = new float[]{0f}; + assertTrue(ArrayUtils.isSorted(array)); + + array = new float[]{-1f, 0f, 0.1f, 0.2f}; + assertTrue(ArrayUtils.isSorted(array)); + + array = new float[]{-1f, 0.2f, 0.1f, 0f}; + assertFalse(ArrayUtils.isSorted(array)); + } + + @Test + public void testIsSortedLong() { + long[] array = null; + assertTrue(ArrayUtils.isSorted(array)); + + array = new long[]{0L}; + assertTrue(ArrayUtils.isSorted(array)); + + array = new long[]{-1L, 0L, 1L}; + assertTrue(ArrayUtils.isSorted(array)); + + array = new long[]{-1L, 1L, 0L}; + assertFalse(ArrayUtils.isSorted(array)); + } + + @Test + public void testIsSortedDouble() { + double[] array = null; + assertTrue(ArrayUtils.isSorted(array)); + + array = new double[]{0.0}; + assertTrue(ArrayUtils.isSorted(array)); + + array = new double[]{-1.0, 0.0, 0.1, 0.2}; + assertTrue(ArrayUtils.isSorted(array)); + + array = new double[]{-1.0, 0.2, 0.1, 0.0}; + assertFalse(ArrayUtils.isSorted(array)); + } + + @Test + public void testIsSortedChar() { + char[] array = null; + assertTrue(ArrayUtils.isSorted(array)); + + array = new char[]{'a'}; + assertTrue(ArrayUtils.isSorted(array)); + + array = new char[]{'a', 'b', 'c'}; + assertTrue(ArrayUtils.isSorted(array)); + + array = new char[]{'a', 'c', 'b'}; + assertFalse(ArrayUtils.isSorted(array)); + } + + @Test + public void testIsSortedByte() { + byte[] array = null; + assertTrue(ArrayUtils.isSorted(array)); + + array = new byte[]{0x10}; + assertTrue(ArrayUtils.isSorted(array)); + + array = new byte[]{0x10, 0x20, 0x30}; + assertTrue(ArrayUtils.isSorted(array)); + + array = new byte[]{0x10, 0x30, 0x20}; + assertFalse(ArrayUtils.isSorted(array)); + } + + @Test + public void testIsSortedShort() { + short[] array = null; + assertTrue(ArrayUtils.isSorted(array)); + + array = new short[]{0}; + assertTrue(ArrayUtils.isSorted(array)); + + array = new short[]{-1, 0, 1}; + assertTrue(ArrayUtils.isSorted(array)); + + array = new short[]{-1, 1, 0}; + assertFalse(ArrayUtils.isSorted(array)); + } + + @Test + public void testIsSortedBool() { + boolean[] array = null; + assertTrue(ArrayUtils.isSorted(array)); + + array = new boolean[]{true}; + assertTrue(ArrayUtils.isSorted(array)); + + array = new boolean[]{false, true}; + assertTrue(ArrayUtils.isSorted(array)); + + array = new boolean[]{true, false}; + assertFalse(ArrayUtils.isSorted(array)); + } + } diff --git a/src/test/java/org/apache/commons/lang3/BooleanUtilsTest.java b/src/test/java/org/apache/commons/lang3/BooleanUtilsTest.java index f1570809d..d3464b7ae 100644 --- a/src/test/java/org/apache/commons/lang3/BooleanUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/BooleanUtilsTest.java @@ -1006,5 +1006,13 @@ public void testOr_object_validInput_3items() { Boolean.TRUE }) .booleanValue()); } + + @Test + public void testCompare(){ + assertTrue(BooleanUtils.compare(true, false) > 0); + assertTrue(BooleanUtils.compare(true, true) == 0); + assertTrue(BooleanUtils.compare(false, false) == 0); + assertTrue(BooleanUtils.compare(false, true) < 0); + } } diff --git a/src/test/java/org/apache/commons/lang3/CharUtilsTest.java b/src/test/java/org/apache/commons/lang3/CharUtilsTest.java index b2adcb36d..94acbcdf4 100644 --- a/src/test/java/org/apache/commons/lang3/CharUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/CharUtilsTest.java @@ -354,5 +354,11 @@ public void testIsAsciiAlphanumeric_char() { } } } - + + @Test + public void testCompare() { + assertTrue(CharUtils.compare('a', 'b') < 0); + assertTrue(CharUtils.compare('c', 'c') == 0); + assertTrue(CharUtils.compare('c', 'a') > 0); + } } diff --git a/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java b/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java index e9ec47da8..e40293c48 100644 --- a/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java @@ -1359,4 +1359,31 @@ public void testLang381() { assertTrue(Float.isNaN(NumberUtils.max(bF))); } + @Test + public void compareInt() { + assertTrue(NumberUtils.compare(-3, 0) < 0); + assertTrue(NumberUtils.compare(113, 113)==0); + assertTrue(NumberUtils.compare(213, 32) > 0); + } + + @Test + public void compareLong() { + assertTrue(NumberUtils.compare(-3L, 0L) < 0); + assertTrue(NumberUtils.compare(113L, 113L)==0); + assertTrue(NumberUtils.compare(213L, 32L) > 0); + } + + @Test + public void compareShort() { + assertTrue(NumberUtils.compare((short)-3, (short)0) < 0); + assertTrue(NumberUtils.compare((short)113, (short)113)==0); + assertTrue(NumberUtils.compare((short)213, (short)32) > 0); + } + + @Test + public void compareByte() { + assertTrue(NumberUtils.compare((byte)-3, (byte)0) < 0); + assertTrue(NumberUtils.compare((byte)113, (byte)113)==0); + assertTrue(NumberUtils.compare((byte)123, (byte)32) > 0); + } }