Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a generic method that merges arrays of any type?

Tags:

java

generics

I have a method that takes two arrays and merges them with elements in natural order. I was wondering if it is possible to make it generic so it can take arrays of any type and merge them into an array of the same type?

Right now I'm able to construct only an array of Object

public static void main(String[] args) {

    Integer[] i1 = {1, 3, 5, 7, 9};
    Integer[] i2 = {2, 4, 6, 8, 10, 12, 14};

    String[] s1 = {"A", "C", "E", "G"};
    String[] s2 = {"B", "D", "F"};

    System.out.println(Arrays.toString(mergeAndSortArrays(i1, i2)));
    System.out.println(Arrays.toString(mergeAndSortArrays(s1, s2)));
}

public static<T extends Comparable<T>> Object[] mergeAndSortArrays(T[] a, T[] b) {
    final Object[] merged = new Object[a.length + b.length];

    int aPos = 0, bPos = 0, curIndex = -1;

    while (++curIndex < merged.length) {

        int comp = a[aPos].compareTo(b[bPos]);
        merged[curIndex] = (comp < 0) ? a[aPos++] : b[bPos++];

        if (aPos == a.length) {
            while (bPos < b.length) {
                merged[++curIndex] = b[bPos++];
            }
            break;
        }

        if (bPos == b.length) {
            while (aPos < a.length) {
                merged[++curIndex] = a[aPos++];
            }
            break;
        }
    }

    return merged;
}
like image 800
jimmayhem Avatar asked Mar 01 '23 15:03

jimmayhem


2 Answers

You can't create an array of generic type in Java, but you can use a creator lambda:

public static<T extends Comparable<T>> T[] mergeAndSortArrays(
    T[] a, 
    T[] b, 
    IntFunction<T[]> arrayCreator
) {
    final T[] merged = arrayCreator.apply(a.length + b.length);

    ...
}

and then:

mergeAndSortArrays(i1, i2, Integer[]::new)
mergeAndSortArrays(s1, s2, String[]::new)

Or alternatively, you have Class<T> itemClass as method parameter (instead of the lambda) and then use (T[]) Array.newInstance(itemClass, a.length + b.length) to create new array.

If you want to avoid additional method arguments (like creator lambda or item class), you can use reflection to retrieve array item type:

final Class<?> itemClass = a.getClass().getComponentType();
final T[] merged = (T[]) Array.newInstance(itemClass, a.length + b.length);

And of course you can also use an existing library for this, like Apache Commons:

final T[] merged = org.apache.commons.lang3.ArrayUtils.addAll(a, b);
// ...
like image 166
Alex Shesterov Avatar answered Apr 26 '23 20:04

Alex Shesterov


If you create the mergedArray out of the type from a, it can look like this.

public static <T extends Comparable<T>> T[] mergeAndSortArrays(T[] a, T[] b) {
    final T[] merged = (T[])Array.newInstance(a.getClass().getComponentType(), a.length + b.length);
like image 27
Benjamin Schüller Avatar answered Apr 26 '23 21:04

Benjamin Schüller