Set rank of array at runtime - java

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?

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.

ArrayList of 2 Dimensional arrays

I created a very simple program to create an ArrayList of 2 Dimensional arrays of floats.
But adding new elements in the list seems to overwrite or corrupt previous elements.
What am i doing wrong and how should this functionality be implemented?
import java.util.ArrayList;
public class multiDArrayTest {
public static void main(String[] args) {
float[][] coeff = new float[3][6];
ArrayList<float[][]> basisCoeffs;
basisCoeffs = new ArrayList<float [][]>(2);
coeff[0][0] = 0;
coeff[0][1] = 100;
coeff[0][2] = -50;
basisCoeffs.add(coeff);
coeff[0][0] = 50;
coeff[0][1] = 200;
coeff[0][2] = -400;
basisCoeffs.add(coeff);
System.out.println(basisCoeffs.get(0)[0][0]);
System.out.println(basisCoeffs.get(0)[0][1]);
System.out.println(basisCoeffs.get(0)[0][2]);
//I should get 0 100 -50 50, but i don't? Where does it go ??
System.out.println(basisCoeffs.get(1)[0][0]);
System.out.println(basisCoeffs.get(1)[0][1]);
System.out.println(basisCoeffs.get(1)[0][2]);
}
}
Here you add the array to the ArrayList, you modify that array, then you add it to the ArrayList a second time. So you have two copies of the same array in the ArrayList. I think you are confusing primitives and objects here. Arrays are objects, so they can be modified. When you get the elements out of the ArrayList, you see both elements point to that same array, which you modified, so you get the modified values back out. If you don't want that behavior, just clone the array when you add it to the ArrayList. Something like basicCoeffs.add(coeff.clone());.
What happens is that you have the coeff array with the first values, you add it to the list and everything is fine, but when you edit coeff again before adding it to the list, you also edit the one that is in position 0 of the list, since both coeff as the element in position 0 of the list they refer to the same object in Java. One option would be to create a copy and another to have the two arrays separately. Also, since I observe that your dimensions are static, you can directly add the values to the designated positions, for example:
import java.util.ArrayList;
public class multiDArrayTest {
public static void main(String[] args) {
ArrayList<float[][]> basisCoeffs = new ArrayList<float [][]>(2);
basisCoeffs.add(new float[3][6]);
basisCoeffs.add(new float[3][6]);
// First values of coeffs
basisCoeffs.get(0)[0][0] = 0;
basisCoeffs.get(0)[0][1] = 100;
basisCoeffs.get(0)[0][2] = -50;
// Second values of coeffs
basisCoeffs.get(1)[0][0] = 50;
basisCoeffs.get(1)[0][1] = 200;
basisCoeffs.get(1)[0][2] = -400;
System.out.println(basisCoeffs.get(0)[0][0]);
System.out.println(basisCoeffs.get(0)[0][1]);
System.out.println(basisCoeffs.get(0)[0][2]);
System.out.println(basisCoeffs.get(1)[0][0]);
System.out.println(basisCoeffs.get(1)[0][1]);
System.out.println(basisCoeffs.get(1)[0][2]);
}
}
Arrays in java are Mutable and pass by reference (well, pass by value of reference). this means is you change an element in an array, the reference is changed. So what do we have to do to avoid these side effects?
You can encapsulate Lists and arrays and just add a copy of objects into arrays.
if you're using Java 9 or later you can use List<float[][]> basisCoeffs = List.of(coeff) to add its Item as an immutable list.
you can read more about mutables and immutables here: Immutable class?

Create empty array without using List<object>

If I want to create an "unlimited" array I know I can use a list (There is a lot of information on this and other forums)
But what if I don't want to make a list? Is there another way?
Because I want to use a float array in another function and it's kind of a hassle to use a list in this case.
This is what I wrote so far with the listing
List<Float> listfloat = new ArrayList();
listfloat.add((float)0.1); //example
listfloat.add((float)1.2);
float data[]= new float[listfloat.size()];
for(int i = 0; i < listfloat.size(); ++i)
{
data[i] = listfloat.get(i);
}
return data ;
But I would prefer something like this
float data[]; //unknown size
for(i=0 ; i< sizeiwant; i++)
{
data[i] = mydata;
}
return data ;
I know that it will work! I just want to optimise my coding =)
Thank you for reading =)
There are 2 ways you can do this:
You could convert a list to an Array using list.ToArray()
You could dynamically resize the array by changing the size of the array every time you add an element to the array. Here is how you would do that:
//initialize array of size 10.
int[] array=new int[10];
//make copy of array
int[] arrayCopy=array.clone();
//expand array size by 1
array=new int[array.length+1];
//give value to new array index
array[array.length-1]=0;
//copy values from 'arrayCopy' to array
for(int x=0;x<arrayCopy.length;x++){
array[x]=arrayCopy[x];
}
Hope this helped.
With the information you provided I would recommend to use an Array and create a method that is called when your array is full and returns a copy of the original array with more space in this way is you are kind of simulating dynamic size allocation.
Arrays in java are fixed-size, so your second piece of code is never going to work.
If you want a data type that can resize, you should use an ArrayList. On the other hand, there are times when using primitive array like a float[] is quicker and more convenient.
As a result, the need to convert between List<Float> and float[] in the way you do it in the first block of code is fairly common, and there is no way to do it in one line (unless you use an external library).
I advise writing a utility method to do the conversion
public static float[] listToArray(List<Float> list) {
int size = list.size();
float[] temp = new float[size];
for (int i = 0; i < size; i++)
temp[i] = list.get(i);
return temp;
}
(This method could be improved, as it has poor performance for a LinkedList where get is linear).
Annoyingly, you need 8 methods like this for the 8 primitive types, and 8 methods to do the conversions in the other direction. As things stand at the moment, there is no way to write generic code over primitive types, so code duplication like this is common.

Common elements of muiltiple arrays but not using Lists

Is there a way i could return in an array the common elements of 2 or more arrays? I know having some of the methods under lists could do it but is there a way to do it by only using arrays? I made my own get and length btw since i am creating a an array called OrderedIntList.
Example would be:
1,3,5
1,6,7,9,3
1,3,10,11
Result: 1,3
I tried this and it outputs the common elements between two arrays and not all.
I know there's something wrong but i do not how to make it work like it suppose to work :(
//returns the common elements of inputted arrays
public static OrderedIntList common(OrderedIntList ... lists){
int[] list = new int[10];
for(int x = 1; x <= lists.length -1; x++){
for(int q = 0; q < lists[0].length()-1; q++) {
for(int z = 0; z < lists[x].length(); z++) {
if (lists[0].get(q)==lists[x].get(z)){
list[q] = lists[0].get(q);
}
}
}
}
OrderedIntList newlist = new OrderedIntList(list);
return newlist;
}
This can be an easy algorithm to solve it...
1) Instantiate an instance variable of type array called
"commonElements" pointing to the elements of the first Array. At the
beginning these are your common elements.
2) Create a method call getCommonElements(int[] commonElements,
int[] newList). This method manipulates the commonElements array to leave
it with only the common elements between the two. (p.s Use a temporary
array to achieve this if you find it easier)
3) Iterate over all the arrays present in "lists" starting from the
second array.
4) call the method at point 2 for each array .
All the difficult part for you it's to implement a method that given 2 arrays finds the common elements!
You can use
org.apache.commons.collections.CollectionUtils.intersection(java.util.Collection a, java.util.Collection b)
to get the intersection of two lists (elements presents in both lists)
And to pass your array as a Collection: java.util.Arrays.asList(Object[] a);
But working on arrays is tedious, at best. You should consider why you don't want to use a Collection...
As a partial answer, you're probably doing too much work by fully reimplementing an OrderedIntList the way you're doing, since ArrayList and friends already come with sorting baked in via the Collections class.
import java.util.Collections;
public class OrderedIntList extends ArrayList<Integer> {
#override // to effect sorted inserts
public void add(Integer i) {
this.add(i);
Collections.sort(this);
// done.
}
}
Wanting to do this for pure arrays is a nice exercise, but then you'll be better of implementing sorting properly with a quick sort (you can't websearch for a java implementation of that without getting a million results) or an insert sort (equally websearchable), and follow the same recipe.
any time you push a number into the array:
guess where the number goes (although that's optional),
insert the number,
resort your array if you know your guess wasn't perfect.

Java: 2D array of arraylists?

I am working on a sudoku solving program and I need an arraylist that holds the numbers 1 thru 9 for each of the squares on the 9x9 board. Each of these arraylists correspond to the possible numbers that could go in that square, if a number can not go in that square, it is removed from the list.
I want to be able to pull up the arraylist of the current square it is working on, like for example if I wanted to remove the number 7 from the arraylist corresponding to square (3,5)
arrayOfLists[3][5].remove(Integer.valueOf(7));
However I can't figure out how to do this. When I try to create the array I am getting this error on the line where I declare my array of arraylists
Cannot create a generic array of ArrayList
Here is my code:
//create arraylist
ArrayList<Integer> nums = new ArrayList<Integer>();
//fill arraylist with numbers 1-9
for (int i = 1; i < 10; i++) {
nums.add(i);
}
//create 9x9 array of arraylists
ArrayList<Integer>[][] array = new ArrayList<Integer>[9][9];
//fill each element of array with arraylist of numbers 1-9
for(int i = 0; i<9; i++){
for(int j = 0; j<9; j++){
array[i][j] = nums;
}
}
}
Am I doing this incorrectly or is it not possible to create an array of arraylists? If it is not possible, how should I do this then?
Anytime I see a list of lists, alarm bells start ringing. The situations where you actually want such a thing are rare indeed, and this is not one of them.
You've got a fixed board consisting of 9 fixed squares, columns and rows, each position of which may take a number 1-9.
Use an array for all of these concepts, because they are fixed in size and you need direct access to each element - collections offer no benefit and would be a hindrance. Use logic (possibly sets) to ensure numbers are used only once in each zone.
Use a bit field instead of an array list. That is, use an integer where bits 1-9 represent the possibilities of the numbers. Testing, adding, removing a single number is O(1), and it has a fixed memory size. Encapsulate the integer in its own object that knows the operations.
A few things:
1) In your for loop, array[i][j] = nums; This is going to result in the same object in each element of the array. If you call remove() on one element of the array, it's going to affect all the others. You want to build a separate list object for each element.
2) Program to interfaces; declare nums as a List as opposed to ArrayList.
3) Use a List of Lists as opposed to any array of Lists.
List<List<List<Integer>>> list = new ArrayList<List<List<Integer>>>();
for(int i = 0; i<9; i++){
List<List<Integer>> row = new ArrayList<List<Integer>>();
for(int j = 0; j<9; j++){
List<Integer> nums = new ArrayList<Integer>();
for (int k = 1; k < 10; k++) {
nums.add(i);
}
row.add(nums);
}
list.add(row);
}
// You can still get an element by index
int x = list.get(3).get(1).remove(6);
But this is kind of unwieldy. You might want to consider writing a class that represents the board. That way you'll at least have operations that better abstract this.
You could completely remove the use 2d stuff and keep a single list by giving each square a unique number from 1...81. So if you are working with 3,5 cell that means it's the 9*2+5 = 23rd item in the list. That will greatly simplify the list manipulation. You could use a single method to give the unique cell index given the (3,5) kind of reference
OK, I'm going to post this as an answer since it seems to work for me and I haven't yet seen any pitfalls.
private static class IntegerArrayList extends ArrayList<Integer> {
IntegerArrayList () { super(); }
IntegerArrayList (Collection<? extends Integer> c) { super(c); }
IntegerArrayList (int initialCapacity) { super(initialCapacity); }
}
Now you can say something like
IntegerArrayList[][] array = new IntegerArrayList[9][9];
and elements like array[1][2] will inherit all the ArrayList methods (array[1][2].remove(something) works fine). I made the class private static thinking you could nest it in some other class if that's the only place you'll use it, but you can make it public if you like. Also, I copied all three constructors from ArrayList; you could eliminate unneeded ones but I don't see a compelling reason to.
I think the issue is that new ArrayList<Integer>[9][9] is prohibited because it would create an array that wouldn't do type checking (because of "type erasure"). But I think adding your own non-generic type that inherits from ArrayList<Integer> restores the type safety.
But I'm not a generic expert, and it wouldn't surprise me if someone more knowledgeable than I spots a problem with this solution. But it seemed to work fine for me, with no compiler warnings about unchecked type stuff or anything.
(P.S. I'm posting this as a possible general solution to a problem that gets asked a lot. But in reality, for this particular problem, I might just use a fixed-size array of boolean instead of an ArrayList, like others, or I might even do bit-diddling on integers if speed is a real issue.)

Categories