From 82cc24437f43d07880d8883229477735431e5d02 Mon Sep 17 00:00:00 2001 From: Emmanuel Bourg Date: Wed, 19 Apr 2017 18:53:06 +0200 Subject: [PATCH] LANG-1272: Added shuffle methods to ArrayUtils --- src/changes/changes.xml | 1 + .../org/apache/commons/lang3/ArrayUtils.java | 226 ++++++++++++++++++ .../apache/commons/lang3/ArrayUtilsTest.java | 105 ++++++++ 3 files changed, 332 insertions(+) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 572471732..f16bb2695 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -83,6 +83,7 @@ The type attribute can be add,update,fix,remove. Deprecate classes/methods moved to commons-text MethodUtils.invokeMethod throws ArrayStoreException if using varargs arguments and smaller types than the method defines Add ArchUtils - An utility class for the "os.arch" system property + Add shuffle methods to ArrayUtils diff --git a/src/main/java/org/apache/commons/lang3/ArrayUtils.java b/src/main/java/org/apache/commons/lang3/ArrayUtils.java index afcb27ff7..f0e9f6b82 100644 --- a/src/main/java/org/apache/commons/lang3/ArrayUtils.java +++ b/src/main/java/org/apache/commons/lang3/ArrayUtils.java @@ -22,6 +22,7 @@ import java.util.BitSet; import java.util.Comparator; import java.util.HashMap; import java.util.Map; +import java.util.Random; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; @@ -8445,4 +8446,229 @@ public class ArrayUtils { } return result; } + + /** + * Randomly permutes the elements of the specified array using the Fisher-Yates algorithm. + * + * @param array the array to shuffle + * @see Fisher-Yates shuffle algorithm + * @since 3.6 + */ + public static void shuffle(Object[] array) { + shuffle(array, new Random()); + } + + /** + * Randomly permutes the elements of the specified array using the Fisher-Yates algorithm. + * + * @param array the array to shuffle + * @param random the source of randomness used to permute the elements + * @see Fisher-Yates shuffle algorithm + * @since 3.6 + */ + public static void shuffle(Object[] array, Random random) { + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i), 1); + } + } + + /** + * Randomly permutes the elements of the specified array using the Fisher-Yates algorithm. + * + * @param array the array to shuffle + * @see Fisher-Yates shuffle algorithm + * @since 3.6 + */ + public static void shuffle(boolean[] array) { + shuffle(array, new Random()); + } + + /** + * Randomly permutes the elements of the specified array using the Fisher-Yates algorithm. + * + * @param array the array to shuffle + * @param random the source of randomness used to permute the elements + * @see Fisher-Yates shuffle algorithm + * @since 3.6 + */ + public static void shuffle(boolean[] array, Random random) { + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i), 1); + } + } + + /** + * Randomly permutes the elements of the specified array using the Fisher-Yates algorithm. + * + * @param array the array to shuffle + * @see Fisher-Yates shuffle algorithm + * @since 3.6 + */ + public static void shuffle(byte[] array) { + shuffle(array, new Random()); + } + + /** + * Randomly permutes the elements of the specified array using the Fisher-Yates algorithm. + * + * @param array the array to shuffle + * @param random the source of randomness used to permute the elements + * @see Fisher-Yates shuffle algorithm + * @since 3.6 + */ + public static void shuffle(byte[] array, Random random) { + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i), 1); + } + } + + /** + * Randomly permutes the elements of the specified array using the Fisher-Yates algorithm. + * + * @param array the array to shuffle + * @see Fisher-Yates shuffle algorithm + * @since 3.6 + */ + public static void shuffle(char[] array) { + shuffle(array, new Random()); + } + + /** + * Randomly permutes the elements of the specified array using the Fisher-Yates algorithm. + * + * @param array the array to shuffle + * @param random the source of randomness used to permute the elements + * @see Fisher-Yates shuffle algorithm + * @since 3.6 + */ + public static void shuffle(char[] array, Random random) { + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i), 1); + } + } + + /** + * Randomly permutes the elements of the specified array using the Fisher-Yates algorithm. + * + * @param array the array to shuffle + * @see Fisher-Yates shuffle algorithm + * @since 3.6 + */ + public static void shuffle(short[] array) { + shuffle(array, new Random()); + } + + /** + * Randomly permutes the elements of the specified array using the Fisher-Yates algorithm. + * + * @param array the array to shuffle + * @param random the source of randomness used to permute the elements + * @see Fisher-Yates shuffle algorithm + * @since 3.6 + */ + public static void shuffle(short[] array, Random random) { + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i), 1); + } + } + + /** + * Randomly permutes the elements of the specified array using the Fisher-Yates algorithm. + * + * @param array the array to shuffle + * @see Fisher-Yates shuffle algorithm + * @since 3.6 + */ + public static void shuffle(int[] array) { + shuffle(array, new Random()); + } + + /** + * Randomly permutes the elements of the specified array using the Fisher-Yates algorithm. + * + * @param array the array to shuffle + * @param random the source of randomness used to permute the elements + * @see Fisher-Yates shuffle algorithm + * @since 3.6 + */ + public static void shuffle(int[] array, Random random) { + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i), 1); + } + } + + /** + * Randomly permutes the elements of the specified array using the Fisher-Yates algorithm. + * + * @param array the array to shuffle + * @see Fisher-Yates shuffle algorithm + * @since 3.6 + */ + public static void shuffle(long[] array) { + shuffle(array, new Random()); + } + + /** + * Randomly permutes the elements of the specified array using the Fisher-Yates algorithm. + * + * @param array the array to shuffle + * @param random the source of randomness used to permute the elements + * @see Fisher-Yates shuffle algorithm + * @since 3.6 + */ + public static void shuffle(long[] array, Random random) { + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i), 1); + } + } + + /** + * Randomly permutes the elements of the specified array using the Fisher-Yates algorithm. + * + * @param array the array to shuffle + * @see Fisher-Yates shuffle algorithm + * @since 3.6 + */ + public static void shuffle(float[] array) { + shuffle(array, new Random()); + } + + /** + * Randomly permutes the elements of the specified array using the Fisher-Yates algorithm. + * + * @param array the array to shuffle + * @param random the source of randomness used to permute the elements + * @see Fisher-Yates shuffle algorithm + * @since 3.6 + */ + public static void shuffle(float[] array, Random random) { + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i), 1); + } + } + + /** + * Randomly permutes the elements of the specified array using the Fisher-Yates algorithm. + * + * @param array the array to shuffle + * @see Fisher-Yates shuffle algorithm + * @since 3.6 + */ + public static void shuffle(double[] array) { + shuffle(array, new Random()); + } + + /** + * Randomly permutes the elements of the specified array using the Fisher-Yates algorithm. + * + * @param array the array to shuffle + * @param random the source of randomness used to permute the elements + * @see Fisher-Yates shuffle algorithm + * @since 3.6 + */ + public static void shuffle(double[] array, Random random) { + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i), 1); + } + } } diff --git a/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java b/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java index 9388e2467..a2d3a21ed 100644 --- a/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java @@ -4990,4 +4990,109 @@ public class ArrayUtilsTest { ArrayUtils.toStringArray(array, "valueForNullElements")); } + @Test + public void testShuffle() { + String[] array1 = new String[]{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}; + String[] array2 = ArrayUtils.clone(array1); + + ArrayUtils.shuffle(array1); + Assert.assertFalse(Arrays.equals(array1, array2)); + for (String element : array2) { + Assert.assertTrue("Element " + element + " not found", ArrayUtils.contains(array1, element)); + } + } + + @Test + public void testShuffleBoolean() { + boolean[] array1 = new boolean[]{true, false, true, true, false, false, true, false, false, true}; + boolean[] array2 = ArrayUtils.clone(array1); + + ArrayUtils.shuffle(array1); + Assert.assertFalse(Arrays.equals(array1, array2)); + Assert.assertEquals(5, ArrayUtils.removeAllOccurences(array1, true).length); + } + + @Test + public void testShuffleByte() { + byte[] array1 = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + byte[] array2 = ArrayUtils.clone(array1); + + ArrayUtils.shuffle(array1); + Assert.assertFalse(Arrays.equals(array1, array2)); + for (byte element : array2) { + Assert.assertTrue("Element " + element + " not found", ArrayUtils.contains(array1, element)); + } + } + + @Test + public void testShuffleChar() { + char[] array1 = new char[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + char[] array2 = ArrayUtils.clone(array1); + + ArrayUtils.shuffle(array1); + Assert.assertFalse(Arrays.equals(array1, array2)); + for (char element : array2) { + Assert.assertTrue("Element " + element + " not found", ArrayUtils.contains(array1, element)); + } + } + + @Test + public void testShuffleShort() { + short[] array1 = new short[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + short[] array2 = ArrayUtils.clone(array1); + + ArrayUtils.shuffle(array1); + Assert.assertFalse(Arrays.equals(array1, array2)); + for (short element : array2) { + Assert.assertTrue("Element " + element + " not found", ArrayUtils.contains(array1, element)); + } + } + + @Test + public void testShuffleInt() { + int[] array1 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + int[] array2 = ArrayUtils.clone(array1); + + ArrayUtils.shuffle(array1); + Assert.assertFalse(Arrays.equals(array1, array2)); + for (int element : array2) { + Assert.assertTrue("Element " + element + " not found", ArrayUtils.contains(array1, element)); + } + } + + @Test + public void testShuffleLong() { + long[] array1 = new long[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + long[] array2 = ArrayUtils.clone(array1); + + ArrayUtils.shuffle(array1); + Assert.assertFalse(Arrays.equals(array1, array2)); + for (long element : array2) { + Assert.assertTrue("Element " + element + " not found", ArrayUtils.contains(array1, element)); + } + } + + @Test + public void testShuffleFloat() { + float[] array1 = new float[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + float[] array2 = ArrayUtils.clone(array1); + + ArrayUtils.shuffle(array1); + Assert.assertFalse(Arrays.equals(array1, array2)); + for (float element : array2) { + Assert.assertTrue("Element " + element + " not found", ArrayUtils.contains(array1, element)); + } + } + + @Test + public void testShuffleDouble() { + double[] array1 = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + double[] array2 = ArrayUtils.clone(array1); + + ArrayUtils.shuffle(array1); + Assert.assertFalse(Arrays.equals(array1, array2)); + for (double element : array2) { + Assert.assertTrue("Element " + element + " not found", ArrayUtils.contains(array1, element)); + } + } }