How to create a nested array of arbitrary depth in java? - java

I am trying to create an array of arrays of arrays etc..., except I don't know how many nested levels deep it needs to be until runtime.
Depending on the input, I might need either int[], int[][], int[][][][][][], or anything else. (For context, I am trying to construct an N-dimensional grid for a cellular automaton, where N is passed as a parameter.)
I don't have any code for you because I have no idea how to go about this; I suspect is not possible at all using just arrays. Any help, or alternative solutions, would be appreciated.

You could do this with an Object[], limiting its members to either Object[] or int[].
For example, here's an array that goes three levels deep in one part, and two levels deep in another:
Object[] myarray = new Object[] {
new Object[] { new int[] { 1, 2 },
new int[] { 3, 4 }},
new int[] { 5, 6 }
};
After you've created it, you may want to access members. In your case, you know the depth N up front, so you know at what depth to expect an Object[] and at what depth to expect an int[].
However, if you didn't know the depth, you could use reflection to determine whether a member is another Object[] level or a leaf int[].
if ( myarray[0] instanceof Object[] ) {
System.out.println("This should print true.");
}
EDIT:
Here's a sketch [untested so far, sorry] of a method that access a member of an array of known depth, given an array of indices. The m_root member can be an Object[] or an int[]. (You could relax this further to support scalars.)
public class Grid {
private int m_depth;
private Object m_root;
...
public int get( int ... indices ) {
assert( indices.length == m_depth );
Object level = m_root;
for ( int i = 0; i + 1 < m_depth; ++i ) {
level = ((Object[]) level)[ indices[i] ];
}
int[] row = (int[]) level;
return row[ indices[m_depth - 1] ];
}
}

This should be achievable using Object[], since arrays are objects:
int[] arr = {1,2,3};
int[] arr2 = {1,2,3};
int[] arr3 = {1,2,3};
int[] arr4 = {1,2,3};
Object[] arr5 = {arr, arr2}; // basically an int[][]
Object[] arr6 = {arr3, arr4}; // basically an int[][]
Object[] arr7 = {arr5, arr6}; // basically an int[][][]
// etc.
Note that one array doesn't have to contain arrays of the same dimensions:
Object[] arr7 = {arr5, arr};
To prevent this (and to allow for easier access to the data), I suggest writing a class which has an Object member (which will be your int[] or Object[]) and a depth variable and some nice functions to give you access to what you want.
ArrayLists will also work:
ArrayList array = new ArrayList();
array.add(new ArrayList());
array.add(new ArrayList());
((ArrayList)array.get(0)).add(new ArrayList());
// etc.

As your N increases going with nested arrays becomes less and less advantageous, especially when you have a grid structure. Memory usage goes up exponentially in N with this approach and the code becomes complex.
If your grid is sparsely populated (a lot of cells with the same value) you can instead have a collection of Cell objects where each of these holds a coordinate vector and the integer value of the cell. Every cell that is not in the collection is assumed to have a default value, which is your most common value.
For faster access you can use for example a k-d tree (https://en.wikipedia.org/wiki/K-d_tree) but that depends a bit on your actual use-case.

#Andy Thomas explains how to do this using Object[] for the higher levels of the multidimensional array. Unfortunately, this means that the types are not correct to allow indexing, or indeed to allow element access without typecasts.
You can't do this:
Object[] array = ...
int i = array[1][2][3][4];
To get types that allow you to do the above, you need to create an object whose real type is (for example) int[][][][].
But the flipside is that it is not really practical to use that style of indexing for N dimensional arrays where N is a variable. You can't write Java source code to do that unless you place a bound on N (i.e. up to 5) and treat the different cases individually. That becomes unmanageable very quickly.

You can use Java reflection as Arrays are objects.
public static void main(String[] args) throws InstantiationException,
IllegalAccessException, ClassNotFoundException {
Class<?> intClass = int.class;
Class<?> oneDimensionalArrayClass = Class.forName("[I");
Object oneDimensionalIntArray1 = Array.newInstance(intClass, 1);
Array.set(oneDimensionalIntArray1, 0, 1);
Object oneDimensionalIntArray2 = Array.newInstance(intClass, 1);
Array.set(oneDimensionalIntArray2, 0, 2);
Object oneDimensionalIntArray3 = Array.newInstance(intClass, 1);
Array.set(oneDimensionalIntArray3, 0, 3);
Object twoDimensionalIntArray = Array.newInstance(oneDimensionalArrayClass, 3);
Array.set(twoDimensionalIntArray, 0, oneDimensionalIntArray1);
Array.set(twoDimensionalIntArray, 1, oneDimensionalIntArray2);
Array.set(twoDimensionalIntArray, 2, oneDimensionalIntArray1);
System.out.println(Array.get(Array.get(twoDimensionalIntArray, 1), 0));
}
The class Array with its static methods gives access on items while you can specify the dimension of your arrays with the number of leading "[".

The whole construct of multi-dimensional arrays is just the compiler doing some work for you on a big block of memory (ok as some have commented in java this is multiple blocks of memory). One way to deal with the problem you face is to use nested arraylists at runtime. Another (more performant) way is to just allocate a single-dimensional array of the size you need and do the indexing yourself. You could then hide the indexing code in a method that was passed all the details like an array de-reference.
private int[] doAllocate(int[] dimensions)
{
int totalElements = dimensions[0];
for (int i=1; i< dimensions.length; i++)
{
totalElements *= dimensions[i];
}
int bigOne = new int[totalElements];
return bigOne;
}
private int deReference(int[] dimensions, int[] indicies, int[] bigOne)
{
int index = 0;
// Not sure if this is only valid when the dimensions are all the same.
for (int i=0; i<dimensions.length; i++)
{
index += Math.pow(dimensions[i],i) * indicies[dimensions.length - (i + 1)];
}
return bigOne[index];
}

Fields like you wrote above a checked and created by the compiler. If you want a dynamic data structure during runtime you could create your own data structure. Search for Composite Pattern. A small snippet should show you how it works:
interface IGrid {
void insert(IGrid subgrid);
void insert(int[] values);
}
class Grid implements IGrid {
private IGrid subgrid;
void insert(IGrid subgrid) {this.subgrid = subgrid;}
void insert(int[] values) {/* Do nothing */}
}
class SubGrid implements IGrid {
private int[] values;
void insert(IGrid subgrid) {/* Do nothing */}
void insert(int[] values) {this.values = values;}
}
You could simply create a Subgrid for int[] or a Grid with a Subgrid for int[][]. It's only a rudimental solution, you would have to create some code for working on your automaton's levels and values. I would do it this way. Hope it will help :) And look forward for more solutions^^

Related

Is it possible to Replace/Remove an element from Java Array without creating a new array?

static String[] Student = new String[6]; //My array
First I need to add a list of elements to this array.
Then remove a specific element from the array.
After that add another element to the array.
Can I do these three without creating another new array?
The answer is yes and no. Technically you can accomplish this with a Java array - as Java arrays are not immutable, but you shouldn't - there are other data structures better suited to this.
Here's how you would do it with an array:
public static void main(String[] args)
{
String[] bad = {"a","b","c","d","e","f"};
removeAndAdd(bad, 2, "g");
}
private static void removeAndAdd(String[] arr, int indexOfDel, String toAdd){
removeElement(arr, 2);
arr[arr.length-1] = toAdd;
}
private static void removeElement(String[] arr, int index){
for(int i = index; i < arr.length; i++){
arr[i] = null;
if(i+1 < arr.length) arr[i] = arr[i+1];
}
}
The problem with this code is that depending on what you want the collection for, there are simpler ways to do this or ways to do this with better runtimes.
Runtime - The runtime of the above code is o(n). This is because if you delete an element at the front of the array, then you need to move all of the elements in the array 1 place over - i.e. an operation that is based linearly on the number of elements. There are other collections that provide different better runtimes for deletion but have other tradeoffs. See this website that lists the runtimes for delete for different data structures.
Simplicity - Another reason to avoid using an array for this is that you can have the same functionality with the same runtime but have the functionality built-in for you if you use something like an ArrayList.
ArrayList<String> good = new ArrayList<>(Arrays.asList(new String[]{"a","b","c","d","e","f"}));
good.remove(2);
good.add("g");
In this example, you accomplish the same exact result but you have to write far less code.
See also this article that compares Java arrays vs arraylists.

Can individual array references be made final? [duplicate]

Is there an immutable alternative to the primitive arrays in Java? Making a primitive array final doesn't actually prevent one from doing something like
final int[] array = new int[] {0, 1, 2, 3};
array[0] = 42;
I want the elements of the array to be unchangeable.
Not with primitive arrays. You'll need to use a List or some other data structure:
List<Integer> items = Collections.unmodifiableList(Arrays.asList(0,1,2,3));
My recommendation is to not use an array or an unmodifiableList but to use Guava's ImmutableList, which exists for this purpose.
ImmutableList<Integer> values = ImmutableList.of(0, 1, 2, 3);
As others have noted, you can't have immutable arrays in Java.
If you absolutely need a method that returns an array that doesn't influence the original array, then you'd need to clone the array each time:
public int[] getFooArray() {
return fooArray == null ? null : fooArray.clone();
}
Obviously this is rather expensive (as you'll create a full copy each time you call the getter), but if you can't change the interface (to use a List for example) and can't risk the client changing your internals, then it may be necessary.
This technique is called making a defensive copy.
There is one way to make an immutable array in Java:
final String[] IMMUTABLE = new String[0];
Arrays with 0 elements (obviously) cannot be mutated.
This can actually come in handy if you are using the List.toArray method to convert a List to an array. Since even an empty array takes up some memory, you can save that memory allocation by creating a constant empty array, and always passing it to the toArray method. That method will allocate a new array if the array you pass doesn't have enough space, but if it does (the list is empty), it will return the array you passed, allowing you to reuse that array any time you call toArray on an empty List.
final static String[] EMPTY_STRING_ARRAY = new String[0];
List<String> emptyList = new ArrayList<String>();
return emptyList.toArray(EMPTY_STRING_ARRAY); // returns EMPTY_STRING_ARRAY
As of Java 9 you can use List.of(...), JavaDoc.
This method returns an immutable List and is very efficient.
Another one answer
static class ImmutableArray<T> {
private final T[] array;
private ImmutableArray(T[] a){
array = Arrays.copyOf(a, a.length);
}
public static <T> ImmutableArray<T> from(T[] a){
return new ImmutableArray<T>(a);
}
public T get(int index){
return array[index];
}
}
{
final ImmutableArray<String> sample = ImmutableArray.from(new String[]{"a", "b", "c"});
}
Since Guava 22, from package com.google.common.primitives you can use three new classes, which have a lower memory footprint compared to ImmutableList.
ImmutableIntArray
ImmutableLongArray
ImmutableDoubleArray
They also have a builder. Example:
int size = 2;
ImmutableLongArray longArray = ImmutableLongArray.builder(size)
.add(1L)
.add(2L)
.build();
or, if the size is known at compile-time:
ImmutableLongArray longArray = ImmutableLongArray.of(1L, 2L);
This is another way of getting an immutable view of an array for Java primitives.
If you need (for performance reason or to save memory) native 'int' instead of 'java.lang.Integer', then you would probably need to write your own wrapper class. There are various IntArray implementations on the net, but none (I found) was immutable: Koders IntArray, Lucene IntArray. There are probably others.
The of(E... elements) method in Java9 can be used to create immutable list using just a line:
List<Integer> items = List.of(1,2,3,4,5);
The above method returns an immutable list containing an arbitrary number of elements. And adding any integer to this list would result in java.lang.UnsupportedOperationExceptionexception. This method also accepts a single array as an argument.
String[] array = ... ;
List<String[]> list = List.<String[]>of(array);
No, this is not possible. However, one could do something like this:
List<Integer> temp = new ArrayList<Integer>();
temp.add(Integer.valueOf(0));
temp.add(Integer.valueOf(2));
temp.add(Integer.valueOf(3));
temp.add(Integer.valueOf(4));
List<Integer> immutable = Collections.unmodifiableList(temp);
This requires using wrappers, and is a List, not an array, but is the closest you will get.
In some situations, it will be lighter weight to use this static method from Google Guava library: List<Integer> Ints.asList(int... backingArray)
Examples:
List<Integer> x1 = Ints.asList(0, 1, 2, 3)
List<Integer> x1 = Ints.asList(new int[] { 0, 1, 2, 3})
If you want to avoid both mutability and boxing, there is no way out of the box. But you can create a class which holds primitive array inside and provides read-only access to elements via method(s).
Implement java.util.function.IntUnaryOperator:
class ImmutableArray implements IntUnaryOperator {
private final int[] array;
ImmutableArray(int[] array) {
this.array = Arrays.copyOf(array, array.length);
}
#Override
public int applyAsInt(int index) {
return array[index];
}
}
Access the array: array[i] becomes immutableArray.applyAsInt(i).
I benchmarked primitive for loop retrieval with a modulus operation with 100_000_000 elements. The above PrimitiveArray took ~220ms; there was no significant difference with a primitive array. The same op on ArrayList took 480 ms, and the loading process took 21 seconds, depleted my heap space first try, and I had to increase this setting on the JVM. Loading of PrimitiveArray had taken 2 seconds.
iteration
if you want to iterate, implement Iterable and provide
public java.util.PrimitiveIterator.OfInt iterator() { return Arrays.stream(array).iterator(); }
This provides access to int nextInt method.
From PrimitiveIterator you also get method forEachRemaining(PrimitiveConsumer) which is helpful to replace an existing enhanced for loop.
Iterating manually with PrimitiveIterator.OfInt yielded performance of ~300ms.
While it's true that Collections.unmodifiableList() works, sometimes you may have a large library having methods already defined to return arrays (e.g. String[]).
To prevent breaking them, you can actually define auxiliary arrays that will store the values:
public class Test {
private final String[] original;
private final String[] auxiliary;
/** constructor */
public Test(String[] _values) {
original = new String[_values.length];
// Pre-allocated array.
auxiliary = new String[_values.length];
System.arraycopy(_values, 0, original, 0, _values.length);
}
/** Get array values. */
public String[] getValues() {
// No need to call clone() - we pre-allocated auxiliary.
System.arraycopy(original, 0, auxiliary, 0, original.length);
return auxiliary;
}
}
To test:
Test test = new Test(new String[]{"a", "b", "C"});
System.out.println(Arrays.asList(test.getValues()));
String[] values = test.getValues();
values[0] = "foobar";
// At this point, "foobar" exist in "auxiliary" but since we are
// copying "original" to "auxiliary" for each call, the next line
// will print the original values "a", "b", "c".
System.out.println(Arrays.asList(test.getValues()));
Not perfect, but at least you have "pseudo immutable arrays" (from the class perspective) and this will not break related code.
Well.. arrays are useful to pass as constants (if they were) as variants parameters.

defining an array size without hardcoding in Java

I'm having a problem where I cannot initialize an array without hard-coding it in Java.
So this is the hard-code version which works:
int numberOfElements = inputFromFile(args[0], myArray);
int [] myArray = new int[1000];
inputFromFile is basically going to be a method I'm going to write that can read the numberOfElements from a textfile along with my program.
I tried fixing it without hardcoding and got my result to be this:
int numberOfElements = inputFromFile(args[0], myArray);
int [] myArray = new int[numberOfElements];
Problem remains that Eclipse wants me to initialize myArray which is an integer array. Is there any good fixes without hard-coding? Any suggestion would be great.
Use an ArrayList, instead? Java, like C, requires constant sized arrays.
You need to initialize an array before using. You are aware of that, i assume.
If you dont know the size of your data, ie: you wont know how big the array size will be, then you will need to use ArrayList<T> which uses array internally and manages reallocation of array size for you.
If you have to use an array, you will have to maintain the array size yourself. as the array grows, you might run out of buckets if you dont set up enough space for the data ie: IndexOutOfBoundsException etc. Then you need to create a new array copy the content of the current array and then continue. All this is done for you in ArrayList, that s the benefit. Saves you time and implementation. Moreover, there is a concept called load factor which is used to expand the array.
Load factor for array is usually:
(j * 3) / 2 + 1 // j for the current length of the array.
FYI: Copying of array becomes very expensive if you data grows very big.
int numberOfElements = inputFromFile(args[0], myArray);
int [] myArray = new int[1000];
By looking at your code, your order of statements is wrong and should be :
int [] myArray = new int[1000];
int numberOfElements = inputFromFile(args[0], myArray);
you are passing myArray to a method before declaring and initializing it.
ArrayList<Integer> s = new ArrayList<Integer>();
int numberOfElements = inputFromFile(args[0], myArray);
This would be better. Then you need to change your method signature as follows:
public void inputFromFile(String fileName, ArrayList<Integer> collection){
// your impl.
}
The various way to use and declare arrays: http://leepoint.net/notes-java/data/arrays/arrays.html
I think you are getting the error because
1) you are using myArray before it is declared.
2) return type of the function inputFromFile does not match int.
I think the following program will answer your question. Here I have a int identifier 'm' which is getting set to a value returned by the 'getNumber' method. Then I am declaring an array of size m.
public class Practise {
public static void main(String args[]){
int m = getNumber();
int [] a = new int[m];
for(int i = 0; i < m; i++)
System.out.println(a[i]);
}
public static int getNumber(){
Scanner input = new Scanner(System.in);
int i = 0;
i = input.nextInt();
return i;
}
}
You can provide the size of your array as command line argument.
Using Dependency Injection of Spring can also be a good way to go, I hope you know how to write a simple bean (constructor injection / setter injection ).
Neither of your code blocks will work, as you try to use myArray before it's declared, or else you try to redeclare myArray. Other than that, if by "hardcode" you mean use a literal value, then no, you don't have to do that. Any of these will work:
int[] arr1 = new int[5];
int size = 10;
int[] arr2 = new int[size];
int sizeLoadedFromFile = loadSizeFrom("/foo/bar/baz");
int[] arr3 = new int[sizeLoadedFromFile];
Note you can also declare an array without an explicit "size" argument if you know the elements ahead of time:
int[] arr4 = {1, 2, 3, 4};
If you think you want an array, but you don't know the size ahead of time, then what you really want is some kind of Collection--probably a List:
List<Integer> list1 = new ArrayList();
list1.add(1);
list1.add(2);
list1.add(3);
list1.add(4);
or more readably, again if you know the elements ahead of time:
List<Integer> list2 = new ArrayList() {{
add(1); add(2); add(3); add(4);
}};
or
List<Integer> list3 = Arrays.asList(1, 2, 3, 4, 5);
The Collections Tutorial should tell you anything else you need to know.
An alternative to using List<Integer> is to use the Trove4j TIntArrayList. This is effectively a wrapper for int[].
However, ArrayList<Integer> is usually fast enough for most use cases.

How to copy a subset from an array of strings to an array of ints using Groovy?

I have a String array in a Groovy class (args to a main method):
String[] args
I'd like to convert the 3rd to the last element into a new array of ints. Is there an easier way to do this in Groovy other than:
final int numInts = args.length - 2
final int [] intArray = new int[numInts]
for (int i = 2; i < args.length; i++) {
intArray[i-2]=Integer.parseInt(args[i])
}
I wanted to do:
final int numInts = args.length - 2
final int [] intArray = new int[numInts]
System.arraycopy(args, 2, intArray, 0, numInts)
But it throws a class cast exception.
Thanks!
This is my solution:
def intArray = args[2..-1].collect { it as int } as int[]
The 2..-1 range selects all elements from the 3rd to the last. The collect method transforms every element of the array using the code in the closure. The last as int[] converts the List of integers that results from the collect method into an array of integers. As Groovy doesn't work with primitive types, the ints will always be stored as java.lang.Integers, but you can work with them, as if they were Java primitives. The conversion from a List to an array is optional. As Collections are first class citizens in Groovy and are much easier to work with as in Java, I'd prefer to work directly with Lists than arrays.
EDIT:
Alternatively, you can replace the collect method with the so called spread operator *., but you have to use the method asType(int) instead of the short version as int:
def intArray = args[2..-1]*.asType(int) as int[]
For your alternative - you try to copy String objects to integers. That is not possible and you get what you deserve - a ClassCastException ;-)
At least within Java - System.arraycopy only works with compatible array types.
Your first approach is not bad. If the code looks too ugly, just hide it in a private method with a signature like:
private int[] parseStrings(String[] args, int start);

Set rank of array at runtime

I was wondering what the simplest way would be to implement an array who's rank is specified at runtime.
The example I am working on stores a array of boolean values for lattice points, and I want the user to be able to chose how many spatial dimensions the model uses at runtime.
I've looked at the Array.newInstance() method:
dimensionOfSpace = userInputValue; // this value comes from GUI or whatever
int latticeLength = 5; // square lattice for simplicity
int[] dimensions = new int[dimensionOfSpace];
for(int i = 0; i < l.length; i++) l[i] = length;
Object lattice = Array.newInstance(boolean.class, dimensions);
But accessing these values in any sort of way seems to require horribly slow methods such as recursively using Array.get until the returned value is no longer an array, i.e. using isArray().
Am I missing an obvious solution here? I would love to be able to access the values in a way similar to foo[i][j][k].
Looks like what you are looking for is for some way to declare how many dimensions an array has at runtime. I don't know how this could be done using a multidimensional ArrayList, or any multidimensional structure where you have to specify the dimensionality at compile time.
The only answer I see is to use a simple linear array wrapped in a class that converts multidimensional coordinate to and from the its position in the underlying array. This is basically how languages such as C stores multidimensional arrays by using one contiguous chunk of memory.
The code would look something like this:
import java.util.*;
class MultiArray<T>{
private int[] dimensions;
private Object[] array;
public MultiArray(int ... dimensions){
this.dimensions=dimensions;
//Utils.product returns the product of the ints in an array
array=new Object[Utils.product(dimensions)];
}
public void set(T value, int ... coords){
int pos=computePos(coords);
array[pos]=value;
}
public T get(int ... coords){
int pos=computePos(coords);
return (T)(array[pos]);
}
private int computePos(int[] coords){
int pos=0;
int factor=1;
for (int i=0;i<coords.length;i++){
pos+=factor*coords[i];
factor*=dimensions[i];
}
return pos;
}
}
class Main{
public static void main(String args[]){
MultiArray<Integer> m=new MultiArray<Integer>(new int[]{5,4,3});
Random r=new Random();
for(int i=0;i<5;i++)
for(int j=0;j<4;j++)
for(int k=0;k<3;k++)
m.set(r.nextInt(),i,j,k);
for(int i=0;i<5;i++){
for(int j=0;j<4;j++){
for(int k=0;k<3;k++)
System.out.print(m.get(i,j,k)+" ");
System.out.println("");
}
System.out.println("\n");
}
}
}
class Utils{
public static int product(int...a){
int ret=1;
for (int x:a) ret*=x;
return ret;
}
}
Checkout Java Collections. It contains a class called ArrayList that grows in size as needed.
One dimensional
List<Boolean> a = new ArrayList<Boolean>();
Two Dimensional
List<List<Boolean>> b = new List<List<Boolean>>();
Three Dimensional
List<List<List<Boolean>>> c = new List<List<List<Boolean>>>();
And you'd access the item as c.get(i).get(j).get(k) instead of c[i][j][k] as in a 3d array. Or even better, wrap it in your own Class, and use a get() method there. So it becomes:
c.get(i, j, k);
Edit:
To have a multi-dimensional list of depth N, remove the Boolean type indictor and simply create lists as
List level1 = new ArrayList();
List level2 = new ArrayList();
List level3 = new ArrayList();
level1.add(level2);
level2.add(level3);
and so on..
I'm going to use the term 'rank' to mean the 'number-of-dimensions' in your array. So a vector has rank 1, a matrix has rank 2 and so on. You've already accepted an answer that by your own admission is not quite what you want. Here's an alternative to settling for less:
Recall that computer memory is essentially linear and that what a compiler does when it gives you arrays is actually take care of transforming an index expression into a linear address. This is simplest to think about if you assume that all arrays are in contiguous memory, not always true. Suppose that you make a declaration such as ARRAY_OF_TYPE[10][10][10], ie it has 1000 elements. Then the element at position [3][5][4] is (my arrays are indexed from 1 not 0 -- change the sums that follow if you want to) at location baseAddress+354*size_of_element_of_TYPE.
I expect you know where I'm going on this by now ...
At run time your program prompts for a list of integers from the user. Each integer specifies the size of one of the dimensions of the array, the number of integers specifies the rank of the array. Your program does some multiplications and you allocate a vector of the right length. OK, you have to write the indexing and de-indexing functions, but these should be fairly straightforward.
et voila you have an array whose rank is established at run time.
I did a quick google search for "java tensor" which came up with DJEP, could that be something which fits your bill?

Categories