What is the best way to take in a multi dimensional array as a method parameter in the form of an object and then reconstruct it as a variable inside that method? The reason I want to pass the array in as an object is because I want my code to be able to use any n dimensional array. I could circumvent this by using method overloading but making hundreds of identical methods just to account for all possible array dimensions seems like a very bad way to do it. However, using an object as a parameter causes a new set of challenges since I have no way to initialize that array since you normally need to explicitly declare an arrays dimensions. Based on some of my research I have figured out a way to determine the dimensions of an array passed in as an object which you can view in the following code snippet.
public static void callTestArray() {
var matrix = new int[][]{{1,2}, {4, 6, 7}};
test(matrix);
}
public static void test(Object obj) {
final int dimensions = dimensionOf(obj);
System.out.println("Dimensions:" + dimensions);
//I can't create a variable from this though since I need to hard code the dimensions of the array
}
/**
* This returns the amount of dimensions an array has.
*/
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;
}
I have been looking around for a while now but I cant find an object that allows me to pass in any n dimensional array in that allows me to easily access all of an arrays typical information? Was this not included in Java or am I just missing it? That being said since 255 is the max amount of dimensions an array can have I could make my own utils class to handle this but it would require a ton of redundancies and effort to handle all cases. I just want to make sure it has not already been made before I waste hours making something like that. Also if anyone has a better way of doing it with any internal java libraries please let me know!
Instead of passing around arrays we more often than not use collections like ArrayList, this allows us some abstraction and allows us to add some common methods to it. Note that ArrayList doesn't extend arrays, it simply implements a list interface.
I recommend the same thing for you, instead of passing around an array, consider encapsulating the array in a class and pass that class around. Use the class to do certain simplifications, for instance you might have a method allowing it to apply a function to each element of the matrix or one to resize the matrix.
You might track your matrix's dimensions in different variables allowing you to resize it without re-allocating the array (like an ArrayList does)
Another advantage of the encapsulation, if you wish to do something different like make a sparse matrix out of it, you could re-implement the underlying code without changing the ways it's used (Like the way ArrayList and LinkedList have the same interface but do things different ways for different use cases)
Your other conditions seem to work for this Matrix object as well as it would arrays, for instance you would pass dimensions into the constructor to create it initially (Although, as I said, you could easily expand it later, especially if you used an ArrayList of ArrayLists for your underlying implementation, if you needed that)
I think the reason it's not included in Java is that it is not very commonly used and quite easy to implement, but if you really don't want to do it yourself, apache has a Matrix implementaiton that looks like it will fit.
We use time series data like hourly tempatures a lot (Often down to 10 second resolution for a day) and so we built our own class that essentially represents a line on a graph with the y axis of "Date", like a linked list but each value is timestamped. This structure is AMAZINGLY useful for us and I often wonder why it's not in Java, but I think I just answered my own question, not used enough.
This is a job for varargs:
public static void main(String[] args) {
var matrix = new int[][]{{1,2}, {4, 6, 7}};
System.out.println("Length is: " + getSize(matrix));
}
public static int getSize(int[]... multiArray) {
return multiArray.length;
}
which prints out:
Length is: 2
Also, unless you have to use an array to hold your int arrays, I would use an ArrayList<int[]> instead. That way you can easily add to your list like:
ArrayList<int[]> multiArray = new ArrayList<>();
multiArray.add(new int[]{1,2,3});
multiArray.add(new int[]{4,5,6});
and then you can get its size by simply calling:
multiArray.size()
Here's my attempt. You use Object as the parameter and then check for the array dimension in the body of the method. In this example, I only limit it to 3D array but you can go up to any dimension.
public class Main{
static void process(Object o){
if (o instanceof int[]){
int[] a = (int[]) o;
System.out.println("1D. length is " + a.length);
} else if (o instanceof int[][]){
int[][] a = (int[][]) o;
System.out.println("2D. row=" + a.length + ", col=" + a[0].length);
} else if (o instanceof int[][][]){
int[][][] a = (int[][][]) o;
System.out.println("3D. row=" + a.length + ", col=" + a[0].length + ", depth=" + a[0][0].length);
} else {
System.out.println("Unsupported array dimension.");
}
}
public static void main(String[] args) {
int[] a = {1,2,3};
int[][] b = {{1,2,3},{1,2,3}};
int[][][] c = {
{ {1,2,3}, {1,2,3} },
{ {1,2,3}, {1,2,3} }
};
process(a);
process(b);
process(c);
}
}
Output:
1D. length is 3
2D. row=2, col=3
3D. row=2, col=2, depth=3
Related
I'm relatively new to C# and the way it handles multidimensional arrays compared to Java is screwing with me.
I'm sure there's a simple solution and that I'm gonna feel really stupid for not realizing it, but I can't seem to find an answer online or figure it out myself.
Consider the following code snippet in java:
Object firstElement(Object[] arr) {
return arr[0];
}
This would return the first element of an array of any number of dimensions; however, in C# this will throw out an error for greater than one dimension because it doesn't recognize a multidimensional array as an object array. The only way to do this I found was by casting the multidimensional array to a System.Array and then using the following code:
object firstElement(Array arr) {
foreach (object obj in arr)
return obj;
}
Is it even possible to do this without a foreach loop in the function? I have tried returning the object using arr.GetValue(0) but this will throw an error again if the array is not one dimensional. Thanks for helping this C# newbie out!
C# expects you to address every dimension in a multidimensional array even if you are meaning to access, say, [0,0].
Object firstElement(Object[] arr) {
return arr[0];
}
For this reason, the code above will throw at compile time.
this code only takes one-dimensional arrays. Try this instead:
Object firstElement(Object[][] arr) {
return arr[0][0];
}
Adjust amount of brackets according to the amount of dimensions.
It is also more common to use the keyword-aliases for primitives like object or int. I do suspect you will replace the Object with an actual class / struct instance or primitive at some point.
object firstElement(object[][] arr) {
return arr[0][0];
}
What I would suggest you reading up on are the two different types of "multidimensional"-arrays: Jagged and actual multidimensional-arrays. The key difference is that each row has to have the same amount of columns in a multidimensional-array whereas the jagged array can be irregular in this regard.
/edit:
I seem have to misunderstood your intention. I believe you try to get every first element of each row. If that is the case then try this one:
List<object> firstElements(object[][] arr)
{
List<object> firsts = new List<object>();
for(int i = 0; i < arr.length; i++)
{
firsts.Add(arr[i][0]);
}
return firsts;
}
This question already has answers here:
How do I do a deep copy of a 2d array in Java?
(7 answers)
Closed 4 years ago.
I'm relatively new to Java, and I just learned this
import java.util.Arrays;
public class Foo {
private int[][] foo;
public Foo(int[][] arr) {
this.foo = arr;
}
#Override
public String toString() {
return Arrays.deepToString(this.foo).replace("],", "],\n");
}
public static void main(String[] args) {
int[][] p = { { 0, 0 }, { 0, 0 } };
Foo g = new Foo(p.clone()); // doesn't work with p nor p.clone()
System.out.println(g);
p[0][0] = 1;
System.out.println(g);
}
}
Here I create an object with a reference to another object, and I can alter the object from the outside since I have the reference to the thing I just passed as an argument to the constructor.
This, although I understand why it happens, seems counterintuitive to me. If I save something as an attribute of an object I expect the object to have a “private” copy not accessible outside.
And I tried with .clone() and doesn't solve it. So the question is...
How is this usually done? Do I need to write a few for loops inside the constructor to get every value out of the argument?
(Or is this a non-issue?)
This last part of the question is important, may be this is a non-issue. Or do people do “something” (a few loops to get a deep clone)?
The problem here is that java doesn't really have 2-D arrays. This:
int[][] x;
is an array of int arrays. It is not a 2D int array, though of course an array of int arrays does feel a lot like a 2D array. For most intents and purposes it iS a 2D int array, unless it isn't, and with clone, it isn't. The clone() impl of an array makes a new array and just copies each and every value, verbatim, into the new array. Which means that your array of int arrays is cloned, but the inner int arrays are not.
When treating int[][] as 'this is a 2D array', yeah, that is unintuitive. When treating int[][] as 'an array of int arrays', it is quite intuitive. You wouldn't expect an array of arraylists, when cloned, to also clone each individual arraylist either.
Soo.. how do you deep-clone an array of arrays (of arrays of arrays)? See How do I do a deep copy of a 2d array in Java? for lots of options :)
Its not duplicated i have read all and nothing suite in my case so please read it and answer it.I have two arrays.One is Vehicle and the other is pin.This is a part of code and it is only the method.
First question :
if i have declare the arrays on the same main out of
this method the way i pass them on the method is right?With other words the parameteres
are good or need (int vehicle[],int pin[]) or something else?
Second question +=
i dont know what it does but i think that in the array pin it takes
as an ecample the pin[1] cost has 10.The number 10 is taken by
getcostosvehicle();(we put it from userinput) so when the array fills
and it hasnt any slot then the costs will be finished.As a result will
have lets say the ended slot is 20 in pin[20] lets say it has 350.The
return statement will give us only the last cost?It would be better to
write return pin[i]; so in that way it will return all the pin with
the whole costs of each one slot,am i right?
Third question
On this code and that i want to write me as an answer could you return
two arrays?I mean return pin[i],vehicle[i]; not only return pin[i];.If
yes,could you do an answer and doesnt need to fill in the vehicle
array.Just to show me if this can happen.
public static int getallcosts(vehicle[],pin[]) {
int costos = 0;
for(int i =0; i < pin.length; i++) {
costos += pin[i].getcostosvehicle();
}
return costos;
}
if i have declare the arrays on the same main out of this method the way i pass them on the method is right?With other words the parameteres are good or need (int vehicle[],int pin[]) or something else?
I'm not sure I understand you correctly but of course getallcosts(vehicle[],pin[]) won't compile, i.e. you need to define the type of the arrays (or the names if vehicle and pin would actually be the types).
It would be better to write return pin[i]; so in that way it will return all the pin with the whole costs of each one slot,am i right?
No, you can only have one return value. If you want to return multiple values then you need to wrap them in an object (array, list, pojo, etc.).
On this code and that i want to write me as an answer could you return two arrays?
See the part above: if you want to return multiple arrays you need to add them so some object and return that object. Since you didn't provide the types for the arrays I'll use another example:
class Result {
String[] strings;
int[] numbers;
}
Result someMethod() {
Result r = new Result();
r.strings = new String[]{"a","b","c"};
r.numbers= new int[]{1,2,3};
return r;
}
First question:
If you are calling a method (so you're not defining it) yuo can write parameters as you do, without type.
Otherwise you need to specify type. In this case you are defining a new method so you need to specify type of parameters.
Second question:
'+=' it's like write
costos = costos + pin[i].getcostosvehicle();
So you will add to the current value of 'costos' the 'costos' of vehicle retrieved by 'getcostosvehicle()';
Third question:
As i know you can't return two Objects of any type in return statement.
So you'll need to reorganize your code to do operation first on an array and return it and then on the other one and return it.
For example you can do a method that have as parameter a generica array do some logic inside and then return it. You will call this method for the first array and then for the second.
Example:
public int[] method(int[] array){
/*do something
*/
return array;
}
Then you will call:
firstArray = method(firstArray);
secondArray = method(secondArray);
If you want more, or i have to change something comment please.
I understand that passing an array to a method is still Pass-By-Value, however the "value" that is passed is the reference of the array. This implies that changing the contents of the array would cause the contents to get updated in an earlier frame (if it's a recursive algorithm), or when it goes back to the main method, for that matter.
import java.util.Arrays;
public class SameArrayPassedOn{
public static void main(String[] args) {
int[] a = {1,1,1};
print(a);
fun(a,0);
print(a);
}
static void fun(int[] b, int count)
{
if(count == 1)
return;
b[0] = b[1] = b[2] = 2;
fun(b,1);
}
static void print(int[] a)
{
for(int x : a)
System.out.print(x + " ");
System.out.println("");
}
}
Output 111 222
However, if you create a new array, like for example, in the code below, since the reference is changed, the updates won't be reflected when you go back to the main method.
import java.util.Arrays;
public class NewArrayCreatedAndReferencePassedOn{
public static void main(String[] args) {
int[] a = {1,1,1};
print(a);
fun(a,0);
print(a);
}
static void fun(int[] b, int count)
{
if(count == 1)
return;
int[] newb = {2,2,2};
fun(newb,1);
}
static void print(int[] a)
{
for(int x : a)
System.out.print(x + " ");
System.out.println("");
}
}
Output 111 111
However, my question is, why such a design was chosen for Arrays. Why couldn't it be that, just like for a primitive data type, say, integer variable, a new int is created every time it's passed inside a function, although we are not explicitly creating a new int, or declaring one. Like for example,
import java.util.Arrays;
public class SameIntPassedOn_ButNewCopyCreatedEachFrame {
public static void main(String[] args) {
int i = 0;
fun(i);
}
static void fun(int b)
{
System.out.println(b);
if(b == 10)
return;
b = b+1;
fun(b);
System.out.println(b);
}
}
Output
0 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1
Had the same been done for arrays, it would've allowed us to have a different copy of the array for each frame of the recursive function, which would've been very handy.
I think it would've been nice to have uniformity in behavior, because at the moment, it looks as though, to achieve the same behavior with Arrays, as is exhibited by primitive data types, such as int, float etc, when passed to a method, it is necessary to use a 'new' keyword, and create a new array before passing on to the method.
However, my question is, why such a design was chosen for Arrays.
There are several main reasons.
The first is performance - it would lead to extremely poor performance if a new copy of the array had to be created every single time a method was called on it, especially for recursive calls.
Had the same been done for arrays, it would've allowed us to have a
different copy of the array for each frame of the recursive function,
which would've been very handy.
The second is that you already have the option of passing a copy of the array if you want to - you can create a copy manually and pass that. This way the programmer has the most control - they can choose to let method calls modify the array, or they can choose to pass a copy, allowing each method call its on version of the array to work with. If we forced the programmer to use a copy all the time, they would lose the option of letting method calls modify the array, which can be extremely useful in some situations. The current design gives the programmer the most options.
Why couldn't it be that, just like for a primitive data type...
The last reason is that an array is not a primitive data type - it is an object. The decision was most likely made to make arrays as consistent as possible with the way other objects in Java behave.
The answer is that all objects, in fact all method arguments are passed by value. Your assessment "Had the same been done for arrays" is wrong because the same is done for arrays. Arrays, like all object references, are passed by value. The copy of a primitive value sent to a method is the same value the caller passed. The copy of an array pointer sent to a method is the same value the caller passed. The copy of any object pointer sent to a method is the same value the caller passed.
It points to the same object, because the pointer is copied by value.
Why, you ask? Because it's simple, it's valid, and really has no downside.
Array is a container (data structure) that hold a set of objects.
Those objects could be huge or small. and the array could contain many objects
imagine with each array reference we do full copy
the language will be extremely slow and inefficient
So the main reason for this is the efficiency
With a third party API I observed the following.
Instead of using,
public static string getString(){
return "Hello World";
}
it uses something like
public static void getString(String output){
}
and I am getting the "output" string assigned.
I am curious about the reason of implementing such functionality. What are the advantages of using such output parameters?
Something isn't right in your example.
class Foo {
public static void main(String[] args) {
String x = "foo";
getString(x);
System.out.println(x);
}
public static void getString(String output){
output = "Hello World"
}
}
In the above program, the string "foo" will be output, not "Hello World".
Some types are mutable, in which case you can modify an object passed into a function. For immutable types (such as String), you would have to build some sort of wrapper class that you can pass around instead:
class Holder<T> {
public Holder(T value) {
this.value = value;
}
public T value;
}
Then you can instead pass around the holder:
public static void main(String[] args) {
String x = "foo";
Holder<String> h = new Holder(x);
getString(h);
System.out.println(h.value);
}
public static void getString(Holder<String> output){
output.value = "Hello World"
}
That example is wrong, Java does not have output parameters.
One thing you could do to emulate this behaviour is:
public void doSomething(String[] output) {
output[0] = "Hello World!";
}
But IMHO this sucks on multiple levels. :)
If you want a method to return something, make it return it. If you need to return multiple objects, create a container class to put these objects into and return that.
I disagree with Jasper: "In my opinion, this is a really ugly and bad way to return more than one result".
In .NET there is a interesting construct that utilize the output parameters:
bool IDictionary.TryGet(key, out value);
I find it very usefull and elegant. And it is the most convenient way to aks if an item is in collection and return it at the same time. With it you may write:
object obj;
if (myList.TryGet(theKey, out obj))
{
... work with the obj;
}
I constantly scold my developers if I see old-style code like:
if (myList.Contains(theKey))
{
obj = myList.Get(theKey);
}
You see, it cuts the performance in half. In Java there is no way to differentiate null value of an existing item from non-existance of an item in a Map in one call. Sometimes this is necessary.
This functionality has one big disadvantage - it doesn't work. Function parameters are local to function and assigning to them doesn't have any impact outside the function.
On the other hand
void getString(StringBuilder builder) {
builder.delete(0, builder.length());
builder.append("hello world");
}
will work, but I see no advantages of doing this (except when you need to return more than one value).
Sometimes this mechanism can avoid creation of a new object.
Example:
If an appropriate object exists anyhow, it is faster to pass it to the method and get some field changed.
This is more efficient than creating a new object inside the called method, and returning and assigning its reference (producing garbage that needs to be collected sometime).
String are immutable, you cannot use Java's pseudo output parameters with immutable objects.
Also, the scope of output is limited to the getString method. If you change the output variable, the caller won't see a thing.
What you can do, however, is change the state of the parameter. Consider the following example:
void handle(Request r) {
doStuff(r.getContent());
r.changeState("foobar");
r.setHandled();
}
If you have a manager calling multiple handles with a single Request, you can change the state of the Request to allow further processing (by other handlers) on a modified content. The manager could also decide to stop processing.
Advantages:
You don't need to return a special object containing the new content and whether the processing should stop. That object would only be used once and creating the object waste memory and processing power.
You don't have to create another Request object and let the garbage collector get rid of the now obsolete old reference.
In some cases, you can't create a new object. For example, because that object was created using a factory, and you don't have access to it, or because the object had listeners and you don't know how to tell the objects that were listening to the old Request that they should instead listen to the new Request.
Actually, it is impossible to have out parameters in java but you can make a work around making the method take on a de-reference for the immutable String and primitives by either writing a generic class where the immutable is the generic with the value and setter and getter or by using an array where element 0 (1 in length) is the value provided it is instantiate first because there are situations where you need to return more than one value where having to write a class just to return them where the class is only used there is just a waste of text and not really re-usable.
Now being a C/C++ and also .Net (mono or MS), it urges me that java does not support at least a de-reference for primitives; so, I resort to the array instead.
Here is an example. Let's say you need to create a function (method) to check whether the index is valid in the array but you also want to return the remainding length after the index is validated. Let's call it in c as 'bool validate_index(int index, int arr_len, int&rem)'. A way to do this in java would be 'Boolean validate_index(int index, int arr_len, int[] rem1)'. rem1 just means the array hold 1 element.
public static Boolean validate_index(int index, int arr_len, int[] rem1)
{
if (index < 0 || arr_len <= 0) return false;
Boolean retVal = (index >= 0 && index < arr_len);
if (retVal && rem1 != null) rem1[0] = (arr_len - (index + 1));
return retVal;
}
Now if we use this we can get both the Boolean return and the remainder.
public static void main(String[] args)
{
int[] ints = int[]{1, 2, 3, 4, 5, 6};
int[] aRem = int[]{-1};
//because we can only scapegoat the de-ref we need to instantiate it first.
Boolean result = validate_index(3, ints.length, aRem);
System.out.println("Validation = " + result.toString());
System.out.println("Remainding elements equals " + aRem[0].toString());
}
puts: Validation = True
puts: Remainding elements equals 2
Array elements always either point to the object on the stack or the address of the object on the heap. So using it as a de-references is absolutely possible even for arrays by making it a double array instantiating it as myArrayPointer = new Class[1][] then passing it in because sometimes you don't know what the length of the array will until the call going through an algorithm like 'Boolean tryToGetArray(SomeObject o, T[][] ppArray)' which would be the same as in c/c++ as 'template bool tryToGetArray (SomeObject* p, T** ppArray)' or C# 'bool tryToGetArray(SomeObject o, ref T[] array)'.
It works and it works well as long as the [][] or [] is instantiate in memory first with at least one element.
in my opinion, this is useful when you have more than one result in a function.