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
Related
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;
}
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 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 am fairly new to Java and was wondering what the difference between the two is. For this example I used arrays:
class testpile {
public static void main(String[] args)
{
int[] a = {1,2,3,4,5,6}; //First array
int[] b = new int[5]; //Second Array
b[0] = 7;
b[1] = 8;
b[2] = 9;
b[3] = 10;
b[4] = 11;
print(a);
print(b);
}
public static void print(int[] a) {
for (int i = 0; i < a.length; i++)
System.out.print(a[i] + " ");
System.out.println();
}
}
I understand that using "new" creates a unique object but what are the advantages of using one over the other?
In your example there's no real difference between the two. The first is mostly just "syntactic sugar" for the latter. In both cases the array is allocated on the heap.
Both of the code creating a int array of size 5/6
In the first case the array is initialized with vale at the time of creation
In second case the value is assigned latter
that's the difference
I understand that using "new" creates a unique object but what are the advantages of using one over the other?
Both constructs do exactly the same thing (with different data, though): Creating an array and filling it with data. In particular, both these arrays are "unique objects".
You'd use the "less literal" one when you do not know the size and the initial values for the element at compile-time.
int[] a = {1,2,3,4,5,6}; //First array
int[] b = new int[5]; //Second Array
They are just two different ways of creating an array. There isn't really any OOP involved here.
The first one is better when you know the values before hand, otherwise the second is better.
The first statement is called array initialization where six int variables are created and each variable is assigned. In second statement, the new keyword create 5 int variables whose initial value is zero.
Using new keyword, you may instantiate an array whenever you require.
int []a=new int[5];
for(int i:a)
System.out.println(i);
a=new int[]{11,22,33};
for(int i:a)
System.out.println(i);
I think the result is same.
But when you create a array with "new" clause, You should assign a specify length of the array.
e.g int[] b = new int[**5**];
And in this sample, you can also assign the value for b[5]. there shouldn't produce compilation error.But the error should occur in the runtime.
In regard to the another method, the length of the array don't need specify. It depend on the element count of array.
Imagine, if you will, a 10x10x10 cube made out of 1x1x1 bricks. Each brick must be accessable by an x,y,z coordinate. For each brick I also need to store a list of names of who own that 'brick'.
As efficiency is an absolute must, I came up with the following idea - A 3d array of vectors.
note- I have made a class which stores a name, and other info (called person)
//declaration
protected Vector<person>[][][] position;
I think I must then allocate memory to the pointer position. I have tried this
position = new Vector<person>[10][10][10];
But am getting an error 'Cannot create a generic array of Vector' I am only familiar with C++ and Java is new to me. I understand java does not like declaring arrays with generic type? Does anyone know how I can get around this problem?
Cheers
No need to complicate things that much! You know the size of the array (10:10:10), so there's no need to go for vectors or other stuff for the bricks. Try using array of objects:
Class Brick {
public Brick(int x, int y, int z){
this.x=x;
this.y=y;
this.z=z;
owners = new ArrayList <String> ();
}
List<String> owners;
int x, y, z; //every brick "knows" its position - you might not need it
}
Code for creating the array:
Public Class Main {
.....
Brick Cube[][][] = new Brick[10][10][10];
for (int x=0; x < 10; x++)
for(int y=0; y < 10; y++)
for(int z=0; z < 10; z++)
{
Cube[x][y][z] = new Brick(x, y, z);
}
//adding an owner to a brick:
Cube[0][0][0].owners.add("Owner");
.....
}
Keep OOP in mind - It makes things much easier!
TODO: add getters/setters
If you did want to go down the route of using a List structure rather than arrays, this should be enough to get you started. This is based off of what #FrustratedWithFormsDes said, but I included the initilization code since it's hard to get the syntax right.
public class Person {
}
class PeopleStorage {
ArrayList<ArrayList<ArrayList<Person>>> data;
public PeopleStorage(int size) {
this.data = new ArrayList<ArrayList<ArrayList<Person>>>(size);
for (int i = 0; i < size; i++) {
ArrayList<ArrayList<Person>> inner = new ArrayList<ArrayList<Person>>(
size);
data.add(inner);
for (int j = 0; j < size; j++) {
ArrayList<Person> inner2 = new ArrayList<Person>(size);
inner.add(inner2);
for (int k = 0; k < size; k++) {
inner2.add(new Person());
}
}
}
}
public Person get(int index1, int index2, int index3)
{
//check indices against size, throw IllegalArgumentException here
return data.get(index1).get(index2).get(index3);
}
public void set(Person person, int index1, int index2, int index3)
{
//check indices against size, throw IllegalArgumentException here
data.get(index1).get(index2).set(index3, person);
}
}
What you are trying to do is impossible in java, because there is no operator overloading (like in C++). In short the [] operator in Java is defined only for arrays and cannot be overloaded. Therefore the only way to access elements inside Vector/ArrayList is through the get() method (or through an Iterator or couple other methods, but you get the picture). Analogically you cannot define multi-dimensional ArrayList that way. What you should do is
ArrayList<ArrayList<ArrayList<Person>>> people = new ArrayList<ArrayList<ArrayList<Person>>>()
and then go and initialize all the internal arrays with nested loops or whatever you wish.
It looks a little bit ugly, and since ArrayList/Vector is a dynamic collection adding for example a new element at the first array would require you to initialize the two nested arrays as well. So you might be better off in design terms with writing some form of a wrapper for that class in order to isolate that logic there.
The difference between ArrayList and Vector in Java is that vector is synchronized (therefore slower) and in the default growth pattern (Vector doubles its size, while ArrayList grows by 50%). Otherwise they are pretty much identical in functionality and complexity of operations.
I think you will want to use an ArrayList instead of a vector. I'm a bit rusty on this, but from what I recall, mixing arrays and generic containers is not a good idea.
You could try this:
position = new ArrayList(10)<ArrayList(10)<ArrayList(10)<Person>>;
but it's rather ugly to read. Accessing data is like this:
person = position.get(1).get(3).get(6); //get someone at x=1, y=3, z=6
Beware I don't have the chance right now to compile this and see if it actually works, so you will want to read the docs on ArrayList but I think this is the direction you could go in...
Update: jhominal has pointed out some news that I forgot, I don't have a Java compiler on hand to verify this, but if you try this solution, take a look at what he says as well.
Note: This is more of an explanation of why generic arrays don't work in Java rather than an answer to your actual question.
Effective Java 2nd Edition deals with generic arrays on page 119 of Chapter 5 (PDF).
Why is it illegal to create a generic
array? Because it isn't typesafe. If
it were legal, casts generated by the
compiler in an otherwise correct
program could fail at runtime with a
ClassCastException. This would
violate the fundamental guarantee
provided by the generic type system.
This is because Java Generics only have types at compile time and insert the appropriate casts so specific operations work at runtime.
The easiest solution to this problem is likely the one Ed.C provided.
I would also go with the object answer by Ed.C, but this seems to work:
#SuppressWarnings("unchecked")
protected Vector<Person>[][][] position = new Vector[10][10][10];
ie, you skip the diamond on the right.