I'm trying to improve performance for a generic function that turns a string into a multidimensional array.
Expected input:
- A string that was generated by the function
Arrays.deepToString()
. - The original array had no null values and did not contain arrays of length 0.
- The array can have any number of dimensions from 1 to 200.
- Sub-arrays may have different length (e.g.
arr[0].length != arr[1].length
)
The function converts the values into the requested data type, which may be any primitive variable or String.
private static String[] arraySeparators;
private static Class[] arrayTypes;
public static <T> Object reverseDeepToString(String str, Class<T> dataType){
int dimensions = 0;
while(str.charAt(dimensions) == '[')
dimensions++;
arraySeparators = new String[dimensions + 1];
String separator = ", ";
for(int x = 2; x <= dimensions; x++)
arraySeparators[x] = separator = ']' + separator + "\\[";
arrayTypes = new Class[dimensions + 1];
Class temp = arrayTypes[2] = Array.newInstance(dataType, 0).getClass();
for(int x = 3; x <= dimensions; x++)
arrayTypes[x] = temp = Array.newInstance(temp, 0).getClass();
str = str.substring(dimensions, str.length() - dimensions);
Object r = createArrayRecursive(str, dimensions, dataType);
arraySeparators = null;
arrayTypes = null;
return r;
}
private static <T> Object createArrayRecursive(String str, int dimension, Class<T> dataType){
if(dimension == 1){
String[] s = str.split(", ");
Object result = Array.newInstance(dataType, s.length);
for(int x = 0; x < s.length; x++){
if(dataType == String.class) Array.set(result, x, s[x]);
else if(dataType == int.class) Array.set(result, x, Integer.parseInt(s[x]));
else if(dataType == double.class) Array.set(result, x, Double.parseDouble(s[x]));
else if(dataType == float.class) Array.set(result, x, Float.parseFloat(s[x]));
else if(dataType == long.class) Array.set(result, x, Long.parseLong(s[x]));
else if(dataType == boolean.class) Array.set(result, x, Boolean.parseBoolean(s[x]));
else if(dataType == short.class) Array.set(result, x, Short.parseShort(s[x]));
else if(dataType == byte.class) Array.set(result, x, Byte.parseByte(s[x]));
else if(dataType == char.class) Array.set(result, x, s[x].charAt(0));
}
return result;
}
String[] s = str.split(arraySeparators[dimension]);
Object arr = Array.newInstance(arrayTypes[dimension], s.length);
for(int x = 0; x < s.length; x++)
Array.set(arr, x, createArrayRecursive(s[x], dimension - 1, dataType));
return arr;
}
The problem is that these workarounds to deal with limitations of generic types are slowing down the function significantly compared to the non-generic equivalent:
private static String[] arraySeparators;
public static Object reverseDeepToString(String str){
int dimensions = 0;
while(str.charAt(dimensions) == '[')
dimensions++;
arraySeparators = new String[dimensions + 1];
String separator = ", ";
for(int x = 2; x <= dimensions; x++)
arraySeparators[x] = separator = ']' + separator + "\\[";
str = str.substring(dimensions, str.length() - dimensions);
return createArrayRecursive(str, dimensions);
}
private static Object createArrayRecursive(String str, int dimension){
if(dimension == 1){
String[] s = str.split(", ");
double[] result = new double[s.length];
for(int x = 0; x < s.length; x++)
result[x] = Double.parseDouble(s[x]);
return result;
}
String[] s = str.split(arraySeparators[dimension]);
int[] lengths = new int[dimension];
lengths[0] = s.length;
Object arr = Array.newInstance(double.class, lengths);
for(int x = 0; x < s.length; x++)
Array.set(arr, x, createArrayRecursive(s[x], dimension - 1));
return arr;
}
My question is: is there a way to make a generic function as efficient as a non-generic function, or at least get very close to it?
The only alternative I have in mind is creating lots of copies of the non-generic function (one for each variable type), and have a main function choosing which non-generic function to use, but that will be a very long and ugly code that I try to avoid:
public static <T> Object reverseDeepToString(String str, Class<T> dataType){
if(dataType == int.class) return reverseDeepToString_int(str);
if(dataType == double.class) return reverseDeepToString_double(str);
if(dataType == long.class) return reverseDeepToString_long(str);
if(dataType == String.class) return reverseDeepToString_string(str);
if(dataType == boolean.class) return reverseDeepToString_boolean(str);
...
}