diff --git a/src/main/java/org/apache/commons/lang3/ArrayUtils.java b/src/main/java/org/apache/commons/lang3/ArrayUtils.java index abcb0373de4..4f1c82c2ac2 100644 --- a/src/main/java/org/apache/commons/lang3/ArrayUtils.java +++ b/src/main/java/org/apache/commons/lang3/ArrayUtils.java @@ -9305,6 +9305,262 @@ public static String[] toStringArray(final Object[] array, final String valueFor return map(array, String.class, e -> Objects.toString(e, valueForNullElements)); } + /** + * Concatenates multiple boolean arrays into a single array. + * + *
This method combines all input arrays in the order they are provided, + * creating a new array that contains all elements from the input arrays. + * The resulting array length is the sum of lengths of all non-null input arrays.
+ * + * @param arrays the arrays to concatenate. Can be empty, contain nulls, + * or be null itself (treated as empty varargs) + * @return a new boolean array containing all elements from the input arrays + * in the order they appear, or an empty array if no elements are present + */ + public static boolean[] concat(boolean[]... arrays) { + int totalLength = 0; + for (boolean[] array : arrays) { + if (array != null) { + totalLength += array.length; + } + } + + boolean[] result = new boolean[totalLength]; + int currentPos = 0; + for (boolean[] array : arrays) { + if (array != null && array.length > 0) { + System.arraycopy(array, 0, result, currentPos, array.length); + currentPos += array.length; + } + } + + return result; + } + + /** + * Concatenates multiple char arrays into a single array. + * + *This method combines all input arrays in the order they are provided, + * creating a new array that contains all elements from the input arrays. + * The resulting array length is the sum of lengths of all non-null input arrays.
+ * + * @param arrays the arrays to concatenate. Can be empty, contain nulls, + * or be null itself (treated as empty varargs) + * @return a new char array containing all elements from the input arrays + * in the order they appear, or an empty array if no elements are present + */ + public static char[] concat(char[]... arrays) { + int totalLength = 0; + for (char[] array : arrays) { + if (array != null) { + totalLength += array.length; + } + } + + char[] result = new char[totalLength]; + int currentPos = 0; + for (char[] array : arrays) { + if (array != null && array.length > 0) { + System.arraycopy(array, 0, result, currentPos, array.length); + currentPos += array.length; + } + } + + return result; + } + + /** + * Concatenates multiple byte arrays into a single array. + * + *This method combines all input arrays in the order they are provided, + * creating a new array that contains all elements from the input arrays. + * The resulting array length is the sum of lengths of all non-null input arrays.
+ * + * @param arrays the arrays to concatenate. Can be empty, contain nulls, + * or be null itself (treated as empty varargs) + * @return a new byte array containing all elements from the input arrays + * in the order they appear, or an empty array if no elements are present + */ + public static byte[] concat(byte[]... arrays) { + int totalLength = 0; + for (byte[] array : arrays) { + if (array != null) { + totalLength += array.length; + } + } + + byte[] result = new byte[totalLength]; + int currentPos = 0; + for (byte[] array : arrays) { + if (array != null && array.length > 0) { + System.arraycopy(array, 0, result, currentPos, array.length); + currentPos += array.length; + } + } + + return result; + } + + /** + * Concatenates multiple short arrays into a single array. + * + *This method combines all input arrays in the order they are provided, + * creating a new array that contains all elements from the input arrays. + * The resulting array length is the sum of lengths of all non-null input arrays.
+ * + * @param arrays the arrays to concatenate. Can be empty, contain nulls, + * or be null itself (treated as empty varargs) + * @return a new short array containing all elements from the input arrays + * in the order they appear, or an empty array if no elements are present + */ + public static short[] concat(short[]... arrays) { + int totalLength = 0; + for (short[] array : arrays) { + if (array != null) { + totalLength += array.length; + } + } + + short[] result = new short[totalLength]; + int currentPos = 0; + for (short[] array : arrays) { + if (array != null && array.length > 0) { + System.arraycopy(array, 0, result, currentPos, array.length); + currentPos += array.length; + } + } + + return result; + } + + /** + * Concatenates multiple int arrays into a single array. + * + *This method combines all input arrays in the order they are provided, + * creating a new array that contains all elements from the input arrays. + * The resulting array length is the sum of lengths of all non-null input arrays.
+ * + * @param arrays the arrays to concatenate. Can be empty, contain nulls, + * or be null itself (treated as empty varargs) + * @return a new int array containing all elements from the input arrays + * in the order they appear, or an empty array if no elements are present + */ + public static int[] concat(int[]... arrays) { + int totalLength = 0; + for (int[] array : arrays) { + if (array != null) { + totalLength += array.length; + } + } + + int[] result = new int[totalLength]; + int currentPos = 0; + for (int[] array : arrays) { + if (array != null && array.length > 0) { + System.arraycopy(array, 0, result, currentPos, array.length); + currentPos += array.length; + } + } + + return result; + } + + /** + * Concatenates multiple long arrays into a single array. + * + *This method combines all input arrays in the order they are provided, + * creating a new array that contains all elements from the input arrays. + * The resulting array length is the sum of lengths of all non-null input arrays.
+ * + * @param arrays the arrays to concatenate. Can be empty, contain nulls, + * or be null itself (treated as empty varargs) + * @return a new long array containing all elements from the input arrays + * in the order they appear, or an empty array if no elements are present + */ + public static long[] concat(long[]... arrays) { + int totalLength = 0; + for (long[] array : arrays) { + if (array != null) { + totalLength += array.length; + } + } + + long[] result = new long[totalLength]; + int currentPos = 0; + for (long[] array : arrays) { + if (array != null && array.length > 0) { + System.arraycopy(array, 0, result, currentPos, array.length); + currentPos += array.length; + } + } + + return result; + } + + /** + * Concatenates multiple float arrays into a single array. + * + *This method combines all input arrays in the order they are provided, + * creating a new array that contains all elements from the input arrays. + * The resulting array length is the sum of lengths of all non-null input arrays.
+ * + * @param arrays the arrays to concatenate. Can be empty, contain nulls, + * or be null itself (treated as empty varargs) + * @return a new float array containing all elements from the input arrays + * in the order they appear, or an empty array if no elements are present + */ + public static float[] concat(float[]... arrays) { + int totalLength = 0; + for (float[] array : arrays) { + if (array != null) { + totalLength += array.length; + } + } + + float[] result = new float[totalLength]; + int currentPos = 0; + for (float[] array : arrays) { + if (array != null && array.length > 0) { + System.arraycopy(array, 0, result, currentPos, array.length); + currentPos += array.length; + } + } + + return result; + } + + /** + * Concatenates multiple double arrays into a single array. + * + *This method combines all input arrays in the order they are provided, + * creating a new array that contains all elements from the input arrays. + * The resulting array length is the sum of lengths of all non-null input arrays.
+ * + * @param arrays the arrays to concatenate. Can be empty, contain nulls, + * or be null itself (treated as empty varargs) + * @return a new double array containing all elements from the input arrays + * in the order they appear, or an empty array if no elements are present + */ + public static double[] concat(double[]... arrays) { + int totalLength = 0; + for (double[] array : arrays) { + if (array != null) { + totalLength += array.length; + } + } + + double[] result = new double[totalLength]; + int currentPos = 0; + for (double[] array : arrays) { + if (array != null && array.length > 0) { + System.arraycopy(array, 0, result, currentPos, array.length); + currentPos += array.length; + } + } + + return result; + } + /** * ArrayUtils instances should NOT be constructed in standard programming. Instead, the class should be used as {@code ArrayUtils.clone(new int[] {2})}. *diff --git a/src/test/java/org/apache/commons/lang3/ArrayUtilsConcatTest.java b/src/test/java/org/apache/commons/lang3/ArrayUtilsConcatTest.java new file mode 100644 index 00000000000..b514c16a888 --- /dev/null +++ b/src/test/java/org/apache/commons/lang3/ArrayUtilsConcatTest.java @@ -0,0 +1,189 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.lang3; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +/** + * Tests for ArrayUtils concat methods + */ +class ArrayUtilsConcatTest extends AbstractLangTest { + + @Test + void testBooleanArraysConcat() { + assertArrayEquals( + new boolean[]{}, + ArrayUtils.concat((boolean[]) null, null) + ); + assertArrayEquals( + new boolean[]{true, false, true}, + ArrayUtils.concat(new boolean[]{true, false, true}, null) + ); + assertArrayEquals( + new boolean[]{false, true, false}, + ArrayUtils.concat(null, new boolean[]{false, true, false}) + ); + assertArrayEquals( + new boolean[]{false, true, false, false, true}, + ArrayUtils.concat(new boolean[]{false, true, false}, new boolean[]{false, true}) + ); + } + + @Test + void testCharArraysConcat() { + assertArrayEquals( + new char[]{}, + ArrayUtils.concat((char[]) null, null) + ); + assertArrayEquals( + new char[]{'a', 'b', 'c'}, + ArrayUtils.concat(new char[]{'a', 'b', 'c'}, null) + ); + assertArrayEquals( + new char[]{'b', 'a', 'c'}, + ArrayUtils.concat(null, new char[]{'b', 'a', 'c'}) + ); + assertArrayEquals( + new char[]{'a', 'b', 'c', 'q', 'w'}, + ArrayUtils.concat(new char[]{'a', 'b', 'c'}, new char[]{'q', 'w'}) + ); + } + + @Test + void testByteArraysConcat() { + assertArrayEquals( + new byte[]{}, + ArrayUtils.concat((byte[]) null, null) + ); + assertArrayEquals( + new byte[]{1, 2, 3}, + ArrayUtils.concat(new byte[]{1, 2, 3}, null) + ); + assertArrayEquals( + new byte[]{-3, 2, 1}, + ArrayUtils.concat(null, new byte[]{-3, 2, 1}) + ); + assertArrayEquals( + new byte[]{1, 3, 2, 100, 7}, + ArrayUtils.concat(new byte[]{1, 3, 2}, new byte[]{100, 7}) + ); + } + + @Test + void testShortArraysConcat() { + assertArrayEquals( + new short[]{}, + ArrayUtils.concat((short[]) null, null) + ); + assertArrayEquals( + new short[]{1000, 2000, 3000}, + ArrayUtils.concat(new short[]{1000, 2000, 3000}, null) + ); + assertArrayEquals( + new short[]{-3000, 2000, 1000}, + ArrayUtils.concat(null, new short[]{-3000, 2000, 1000}) + ); + assertArrayEquals( + new short[]{1000, 3000, 2000, 10000, 7000}, + ArrayUtils.concat(new short[]{1000, 3000, 2000}, new short[]{10000, 7000}) + ); + } + + @Test + void testIntArraysConcat() { + assertArrayEquals( + new int[]{}, + ArrayUtils.concat((int[]) null, null) + ); + assertArrayEquals( + new int[]{10000000, 20000000, 30000000}, + ArrayUtils.concat(new int[]{10000000, 20000000, 30000000}, null) + ); + assertArrayEquals( + new int[]{-30000000, 20000000, 10000000}, + ArrayUtils.concat(null, new int[]{-30000000, 20000000, 10000000}) + ); + assertArrayEquals( + new int[]{10000000, 30000000, 20000000, 100000000, 70000000}, + ArrayUtils.concat(new int[]{10000000, 30000000, 20000000}, new int[]{100000000, 70000000}) + ); + } + + @Test + void testLongArraysConcat() { + assertArrayEquals( + new long[]{}, + ArrayUtils.concat((long[]) null, null) + ); + assertArrayEquals( + new long[]{10000000000L, 20000000000L, 30000000000L}, + ArrayUtils.concat(new long[]{10000000000L, 20000000000L, 30000000000L}, null) + ); + assertArrayEquals( + new long[]{-30000000000L, 20000000000L, 10000000000L}, + ArrayUtils.concat(null, new long[]{-30000000000L, 20000000000L, 10000000000L}) + ); + assertArrayEquals( + new long[]{10000000000L, 30000000000L, 20000000000L, 100000000000L, 70000000000L}, + ArrayUtils.concat(new long[]{10000000000L, 30000000000L, 20000000000L}, new long[]{100000000000L, 70000000000L}) + ); + } + + @Test + void testFloatArraysConcat() { + assertArrayEquals( + new float[]{}, + ArrayUtils.concat((float[]) null, null) + ); + assertArrayEquals( + new float[]{1f, .2f, 3.0f}, + ArrayUtils.concat(new float[]{1f, .2f, 3.0f}, null) + ); + assertArrayEquals( + new float[]{3.0f, 1f, .2f}, + ArrayUtils.concat(null, new float[]{3.0f, 1f, .2f}) + ); + assertArrayEquals( + new float[]{1f, .2f, 3.0f, 10.01f, 0.001f}, + ArrayUtils.concat(new float[]{1f, .2f, 3.0f}, new float[]{10.01f, 0.001f}) + ); + } + + @Test + void testDoubleArraysConcat() { + assertArrayEquals( + new double[]{}, + ArrayUtils.concat((double[]) null, null) + ); + assertArrayEquals( + new double[]{1e-300, .2e-300, 3.0e-300}, + ArrayUtils.concat(new double[]{1e-300, .2e-300, 3.0e-300}, null) + ); + assertArrayEquals( + new double[]{3.0e-300, 1e-300, .2e-300}, + ArrayUtils.concat(null, new double[]{3.0e-300, 1e-300, .2e-300}) + ); + assertArrayEquals( + new double[]{1e-300, .2e-300, 3.0e-300, 10.01e-300, 0.001e-300}, + ArrayUtils.concat(new double[]{1e-300, .2e-300, 3.0e-300}, new double[]{10.01e-300, 0.001e-300}) + ); + } + +}