I am wanting to make a method that can take in an array of n dimensions and then do some sorting with that info. The sorting part is out of the scope of this question though since the part I am stuck on is making a method accept an array of n dimensions. Normally you include something like int[] nums as a parameter. However, this does not allow for a scalable dimensional input. I did some research and the following code accurately calculates the dimensions of an array but I am not sure where to go from there since I cant figure out how to initialize an array of n dimensions from just an Object.
public static int dimensionOf(Object arr) {
int dimensionCount = 0;
Class<?> c = arr.getClass(); // getting the runtime class of an object
while (c.isArray()) { // check whether the object is an array
c = c.getComponentType(); // returns the class denoting the component type of the array
dimensionCount++;
}
return dimensionCount;
}
Here is something else to explain my issue lets say someone passes in a 2 dimensional array as the object. If that happened my dimensions variable would be equal to 2 since its using the above code to determine the dimension of the array. The thing I am stuck on is figuring out how to then produce a useable variable. Here you can see I tried to cast the object (which I know is an instance of array) to a 1d array which would through an error since the incoming object is a 2d array.
public static int sortNDimensionalArray(Object obj) {
int dimensions = dimensionOf(obj);
//This means we did not get an array passed in
if(dimensions == 0) return -1;
int[] array = (int[]) obj;
return 1;
}
I tried it out and got this and it works for me:
public static int dimensionOf(Object... args) {
int dim = 0;
Class<?> c = args.getClass();
while(c.isArray()) {
c = c.getComponentType();
dim++;
}
return dim;
}
Related
I need to be able to have an n-dimensional field where n is based on an input to the constructor. But I'm not even sure if that's possible. Is it?
Quick solution: you could approximate it with a non-generic ArrayList of ArrayList of ... going as deep as you need to. However, this may get awkward to use pretty fast.
An alternative requiring more work could be to implement your own type using an underlying flat array representation where you calculate the indexing internally, and providing accessor methods with vararg parameters. I am not sure if it is fully workable, but may be worth a try...
Rough example (not tested, no overflow checking, error handling etc. but hopefully communicates the basic idea):
class NDimensionalArray {
private Object[] array; // internal representation of the N-dimensional array
private int[] dimensions; // dimensions of the array
private int[] multipliers; // used to calculate the index in the internal array
NDimensionalArray(int... dimensions) {
int arraySize = 1;
multipliers = new int[dimensions.length];
for (int idx = dimensions.length - 1; idx >= 0; idx--) {
multipliers[idx] = arraySize;
arraySize *= dimensions[idx];
}
array = new Object[arraySize];
this.dimensions = dimensions;
}
...
public Object get(int... indices) {
assert indices.length == dimensions.length;
int internalIndex = 0;
for (int idx = 0; idx < indices.length; idx++) {
internalIndex += indices[idx] * multipliers[idx];
}
return array[internalIndex];
}
...
}
Here's a nice article that explains how to use reflection to create arrays at run-time: Java Reflection: Arrays. That article explains how to create a one-dimensional array, but java.lang.reflect.Array also contains another newInstance method to create multi-dimensional arrays. For example:
int[] dimensions = { 10, 10, 10 }; // 3-dimensional array, 10 elements per dimension
Object myArray = Array.newInstance(String.class, dimensions); // 3D array of strings
Since the number of dimensions is not known until runtime, you can only handle the array as an Object and you must use the get and set methods of the Array class to manipulate the elements of the array.
Try this:
https://github.com/adamierymenko/hyperdrive
I'm having a problem in my code. I have an object that contains a matrix of integers, and I'm using this matrix as the original "model" to create other matrices. But at the end, my original matrix has a different value, but I'm not changing in any way.
public Matrix generateAdjacencyMatrix(Matrix m)
{
int storedValue;
int fitness;
int[][] auxiliar_matrix = mc.matrixStructure.matrix;
int[] original_ordering = mc.matrixStructure.matrixOrder;
for(int i=0;i<mc.matrixStructure.getMatrixSize();i++)
{
if(m.matrixOrder[i] != original_ordering[i]) //Only changes if the columns have changed
{
for(int j=0;j<mc.matrixStructure.getMatrixSize();j++)
{
storedValue = auxiliar_matrix[j][m.matrixOrder[i]];
auxiliar_matrix[j][m.matrixOrder[i]] = auxiliar_matrix[j][original_ordering[i]];
auxiliar_matrix[j][original_ordering[i]] = storedValue;
}
for(int j=0;j<mc.matrixStructure.getMatrixSize();j++)
{
storedValue = auxiliar_matrix[m.matrixOrder[i]][j];
auxiliar_matrix[m.matrixOrder[i]][j] = auxiliar_matrix[original_ordering[i]][j];
auxiliar_matrix[original_ordering[i]][j] = storedValue;
}
}
}
m.matrix = auxiliar_matrix;
m.setFitness(computeFitness(m.matrix));
return m;
}
This is the method that creates the other matrices. The object "mc" contains my original matrix (mc.matrixStructure.matrix), and exactly after the for loop the value is different.
I am instantiating this object on the constructor method:
public GeneticAlgorithm() throws IOException
{
this.r = new Random();
this.matingPool = new ArrayList<>(populationSize);
this.population = new ArrayList<>(populationSize);
this.nextGeneration = new ArrayList<>(populationSize);
this.mc = new MatrixCreator("CS4006_input_file2.txt");
this.mc.check0or1();
this.mc.checkDiagonalLine();
this.mc.checkSymmetry();
this.auxiliarVector = mc.matrixStructure.matrixOrder;
this.auxiliarMatrix = new Matrix(mc.matrixStructure.getMatrixSize());
this.matrixSize = mc.matrixStructure.getMatrixSize();
}
This is it.
When you do this ...
int[][] auxiliar_matrix = mc.matrixStructure.matrix;
int[] original_ordering = mc.matrixStructure.matrixOrder;
... you are making auxiliar_matrix and original_ordering references to the same objects that mc.matrixStructure.matrix and mc.matrixStructure.matrixOrder refer to. Modifying those objects via one set of references is equivalent to modifying them through the other, so contrary to your assertion, you absolutely are changing your original matrix. To avoid this, you need to copy the arrays.
Moreover, you have that problem twofold with auxiliar_matrix because Java 2D arrays are arrays of arrays, and arrays are objects, too. You need to perform a deep copy of that 2D array to avoid modifying the original object.
Something like this should do it:
int[] original_ordering = Arrays.copyOf(mc.matrixStructure.matrixOrder);
int[][] auxiliar_matrix = Arrays.copyOf(mc.matrixStructure.matrix);
int i;
for (i = 0; i < auxiliar_matrix.length; i += 1) {
auxiliar_matrix[i] = Arrays.copyOf(auxiliar_matrix[i]);
}
When you assign an object to a reference variable, you assign its reference. You do not copy it to that reference.
Thus, after an assignment such as
int[][] auxiliar_matrix = mc.matrixStructure.matrix;
Your auxiliar_matrix reference variable now refers to the matrix to which mc.matrixStructure.matrix refers.
It's the same matrix, residing on the heap.
Now you are changing data inside the object referred to by auxiliar_matrix. For example, here:
auxiliar_matrix[j][original_ordering[i]] = storedValue;
This means the value will be changed in the matrix both it and mc.matrixStructure.matrix are referring to.
If you want to work on a separate copy of your original matrix without affecting it, you have to copy it to a new object first, and then assign this copy to auxiliar_matrix. In this case, it's an array of arrays, so you have to create a new array of the same length, and copy over each of the subarrays using Arrays.copyOf. Beware of trying to use Arrays.copyOf on the array of arrays - the copy is shallow and it will just copy references to the subarrays which would give you the same problem.
I was doing some exercises on arrays, and I was prompted to return a reference to an array after copying it element by element. What does this exactly mean?
My code is the following:
public static int[] cloneArray(int array[])
{
int[] arraycopy = new int[array.length];
for(int i = 0; i < array.length; i++)
{
arraycopy[i] = array[i];
}
return arraycopy;
}
I don't know what I should be returning though as a "reference": should I return an array of ints or an int? Whenever I try to print the array, I get a weird combination of characters and numbers (unless I invoke Arrays.toString()).
"Return a reference to an array" just means "return an array".
Java only returns values, which are either primitives or object references (ie for objects, the value is a reference).
Although Java is based on C, it doesn't sully itself with pointers etc like C does.
In Java, arrays and objects do not act like primitive types such as int. Consider the following code:
public class MyClass {
public static int method1(int ar[]) {
int x = ar[1];
ar[1] = 3;
return x;
}
}
Now suppose that somewhere else, the follow code is executed:
int abcd[] = new int[3];
abcd[0] = 0;
abcd[1] = 1;
abcd[2] = 2;
int d = MyClass.method1(abcd);
System.out.println(abcd[1]);
What would be printed? It's not 1, but 3. This is because the method was not given the data in the array, it was told the location of the array. In other words, it was passed a reference. Because it was using a reference, changing the value of an array index changed its value in the code that called it. This would not have happened if method1 had taken an int as an argument.
Basically, in Java, methods do not accept arrays as arguments or return arrays. They only use references to arrays. The same goes for objects (except for Strings, which are passed by value).
In Java, Objects are only accessed by reference. Just return the Array object.
I'm doing a task for a course in Java programming and I'm not sure how the following thing is working? The method below takes the value from an array and a integer. The integer should be added to the array and then be used outside the method in other methods and so on, but how could this work when the method has no return for the new content of the array? There is a void in the method? Have I missed something? Preciate some help? Is there something about pointers?
public static void makeTransaction(int[] trans, int amount);
Arrays in Java are objects. If you modify the trans array inside the method, the changes will be reflected outside of it1. Eg:
public static void modify(int[] arr)
{
arr[0] = 10;
}
public static void main(...)
{
int x = {1, 2, 3};
System.out.println(x[0]); // prints 1
modify(x);
System.out.println(x[0]); // now it prints 10
}
Note that native arrays can't be dynamically resized in Java. You will have to use something like ArrayList if you need to do that. Alternatively you can change the return type to int[] and return a new array with the new element "appended" to the old array:
public static int[] makeTransaction(int[] trans, int amount)
{
int[] new_trans = Arrays.copyOf(trans, trans.length + 1);
new_trans[trans.length] = amount;
return new_trans;
}
1 It is also worth noting that as objects, array references are passed by value, so the following code has no effect whatsoever outside of the method:
public void no_change(int[] arr)
{
arr = new int[arr.length];
}
You can't add anything to an array. Java arrays have a fixed length. So indeed, what you want to do is impossible. You might make the method return an int[] array, but it would be a whole new array, containing all the elements of the initial one + the amount passed as argument.
If you want to add something to an array-like structure, use an ArrayList<Integer>.
Do you have to keep the method signature as is?
Also, can you be a bit more specific. When you say "the integer should be added to the array", are you referring to the amount argument? If so, then how is that amount added? Do we place it somewhere in the array or is it placed at the end, thus extending the array's length?
As far as pointers go, Java's pointers are implicit, so if you don't have a strong enough knowledge of the language, then it might not be so clear to you. Anyways, I believe that Java methods usually will pass objects by reference, and primitives by value. But, even that isn't entirely true. If you were to assign your object argument to new object, when the method terminates, the variable that you passed to the method is the same after the method executed as it was before. But, if you were to change the argument's member attributes, then when the method terminated those attributes values will be the same as they were inside of the method.
Anyways, back to your question, I believe that will work because an array is an object. So, if you were to do the following:
public static void makeTransaction(int[] trans, int amount)
{
trans[0] = amount;
}
// static int i;
/**
* #param args
*/
public static void main(String[] args)
{
int[] trans = {0,1,3};
makeTransaction(trans, 10);
for(int i = 0; i<trans.length; i++)
{
System.out.println(trans[i]);
}
}
The output of the array will be:
10
1
3
But, watch this. What if I decided to implement makeTransaction like so:
public static void makeTransaction(int[] trans, int amount)
{
trans[0] = amount;
trans = new int[3];
}
What do you think that the output will be? Will it be set to all zero's or will be the same as it was before? The answer is that the output will be the same as it was before. This ties in to what I was saying earlier.
I might've assigned that pointer to a new object in memory, but your copy of the pointer inside of the main method remains the same. It still points to the same place in memory as it did before. When the makeTransaction method terminates, the new int[3] object that I created inside of it is available for garbage collection. The original array remains intact. So, when people say that Java passes objects by reference, it's really more like passing objects' references by value.
I need to be able to have an n-dimensional field where n is based on an input to the constructor. But I'm not even sure if that's possible. Is it?
Quick solution: you could approximate it with a non-generic ArrayList of ArrayList of ... going as deep as you need to. However, this may get awkward to use pretty fast.
An alternative requiring more work could be to implement your own type using an underlying flat array representation where you calculate the indexing internally, and providing accessor methods with vararg parameters. I am not sure if it is fully workable, but may be worth a try...
Rough example (not tested, no overflow checking, error handling etc. but hopefully communicates the basic idea):
class NDimensionalArray {
private Object[] array; // internal representation of the N-dimensional array
private int[] dimensions; // dimensions of the array
private int[] multipliers; // used to calculate the index in the internal array
NDimensionalArray(int... dimensions) {
int arraySize = 1;
multipliers = new int[dimensions.length];
for (int idx = dimensions.length - 1; idx >= 0; idx--) {
multipliers[idx] = arraySize;
arraySize *= dimensions[idx];
}
array = new Object[arraySize];
this.dimensions = dimensions;
}
...
public Object get(int... indices) {
assert indices.length == dimensions.length;
int internalIndex = 0;
for (int idx = 0; idx < indices.length; idx++) {
internalIndex += indices[idx] * multipliers[idx];
}
return array[internalIndex];
}
...
}
Here's a nice article that explains how to use reflection to create arrays at run-time: Java Reflection: Arrays. That article explains how to create a one-dimensional array, but java.lang.reflect.Array also contains another newInstance method to create multi-dimensional arrays. For example:
int[] dimensions = { 10, 10, 10 }; // 3-dimensional array, 10 elements per dimension
Object myArray = Array.newInstance(String.class, dimensions); // 3D array of strings
Since the number of dimensions is not known until runtime, you can only handle the array as an Object and you must use the get and set methods of the Array class to manipulate the elements of the array.
Try this:
https://github.com/adamierymenko/hyperdrive