Java - variable in method not erased after call - java

I really need to explain behavior of code I have created.
Variable preyPred here: private static double[] preyPredLV(double[] preyPred, double[] a, double[] b, int n) is local for method preyPredLV or not?
Because, when I manipulate it during calling of the method, and then I call the method again for different n, it does not assign preyPredDefault as value of preyPred, but it uses its own value from previous call. Shouldn't its previous value be discarded when method returns output value and shouldn't be the new value assigned during next call? Can someone please explain? Thank you
Whole code:
public class Main {
public static void main(String[] args) {
double[] preyPredDefault = {300, 20};
double[] a = {0.1, 0.01};
double[] b = {0.01, 0.00002};
int n = 1;
double[] result = preyPredLV(preyPredDefault, a, b, n);
System.out.println("After "+n+" generations: Hares = "+result[0]+" and Lynx = "+result[1]);
n = 2;
result = preyPredLV(preyPredDefault, a, b, n);
System.out.println("After "+n+" generations: Hares = "+result[0]+" and Lynx = "+result[1]);
}
private static double[] preyPredLV(double[] preyPred, double[] a, double[] b, int n) {
double[] preyPredOld = new double[2];
System.out.println("n = "+n);
System.out.println("preyPred[0] = "+preyPred[0]);
System.out.println("preyPred[1] = "+preyPred[1]);
for(int iteration = 0; iteration < n; iteration++){
preyPredOld[0] = preyPred[0];
preyPredOld[1] = preyPred[1];
preyPred[0] = preyPredOld[0] * (1 + a[0] - a[1]*preyPredOld[1]);
preyPred[1] = preyPredOld[1] * (1 - b[0] + b[1]*preyPredOld[0]);
}
return preyPred;
}
}
Result:
n = 1
preyPred[0] = 300.0
preyPred[1] = 20.0
After 1 generations: Hares = 270.00000000000006 and Lynx = 19.92
n = 2
preyPred[0] = 270.00000000000006
preyPred[1] = 19.92
After 2 generations: Hares = 219.31183648512007 and Lynx = 19.726535847029762

Arrays in Java are not passed as a copy. They are passed as a reference to the array, which is then shared between caller and method.
So if you update the array from within the method, this is an in-place update, and the changes will be visible to whoever else has a reference to that array.
If you want to avoid that, make a "defensive copy" (using Arrays.copyOf) and make changes only to that.

You are passing a reference of the preyPredDefault array to your preyPredLV method, and your method updates this array via the reference you pass. Thus your method modifies the content of that array.
If you don't want preyPredLV to update that array, you can pass it a copy of the array.
double[] result = preyPredLV(Arrays.copyOf(preyPredDefault,preyPredDefault.length), a, b, n);

Related

Confusion on Recursion and why my List isn't staying Updated?

import java.util.*;
public class MyClass {
public static void main(String args[]) {
int[] arr = new int[]{2,3,4,5};
int[] min = new int[]{Integer.MAX_VALUE};
int tgt = 7;
List<Integer> lst = new ArrayList<>();
List<Integer> sol = new ArrayList<>();
recursion(arr, tgt, lst, min, sol);
for (int i = 0; i < sol.size(); i++) {
System.out.println(sol.get(i));
}
}
public void recursion(int[] nums, int tgt, List<Integer> lst, int[] minLen, List<Integer> sol) {
if (tgt < 0) {
return;
}
if (tgt == 0) {
if (lst.size() <= minLen[0]) {
minLen[0] = lst.size();
}
sol = lst;
return;
}
for (int i = 0; i < nums.length; i++) {
List<Integer> cpy = new ArrayList<>(lst);
cpy.add(nums[i]);
recursion(nums, tgt - nums[i], cpy, minLen, sol);
}
}
}
The basic logic of what I'm trying to do is, given an array of numbers and a target, I want to return the smallest list of numbers that can be summed up to the target (in this case I'd want to return either {3,4} or {5,2}. I call a recursive function that breaks down my problem until I reach a base case in which I return or do some work on my sol list. lst is there to build up my current list in that recursive path while sol is there to update whenever I find a new path that is the new minimum length. However, what I think is happening is that when sol updates and returns, it becomes reset so sol is empty when it returns to main. I thought the sol list was being added to the Heap and would persist across all the calls when updated (like the minLen array)? Or am I missing something. What would be a way to get around this while maintaining my logic (I don't want to return a value but would rather have some data structure that just updates and that I could just return from my main function).
When you have a code as follows:
public void recursion(int[] nums, int tgt, List<Integer> lst, int[] minLen, List<Integer> sol) {
//... removed not relevant code
sol = lst;
}
What you are really doing is just assigning sol variable to point to a different object. That doesn't have any affect on the sol variable that you passed as an argument in the main method. That's because java passes arguments by value. In this case value is a reference to the object.
In the recursion method that reference is copied into sol variable (parameter). So, when you assign it a different value (sol = lst), you only update value of this one variable, that is local to the function.
You have two solutions here:
Just add all values into a list that sol (passed as argument) points to.
(better) just return result from within a function and assign it to new variable in main method.
It' usually a bad idea to modify objects passed into the function (unless that's the job of the function - like sort function). It's (almost) always better to return result with a return statement.

Array of static objects get the same value after cicle

I'm testing the result of this code, to realise how the static object creating works.
Basically i understood everything till the last System.out.println(" " + a[0]); I ran the debugger, and i verified that in that point, all of the elements of the array have the same value on num variable.
Can anyone explain me why is it happen?
static class Numero {
private static int sn = 0;
private int num;
public Numero(int n) {
num = n;
++sn;
}
public void setNum(int n) {
num = n;
}
public String toString() {
return "num = " + num + " sn = " + sn;
}
}
public static void main(String[] args) {
Numero[] a = new Numero[3];
Numero x = new Numero(12);
for (int i = 0; i < a.length; i++) {
a[i] = x;
a[i].setNum(i);
System.out.println(" " + a[i]);
}
System.out.println(" " + a[0]);
}
Output:
num = 0 sn = 1
num = 1 sn = 1
num = 2 sn = 1
num = 2 sn = 1
This is because your Numero object is mutable. When you modify it in any way, all references to it are modified as well.
When you call a[i] = x:
You don't create a copy of x and put it in position i.
You do store a reference to x at position i.
So, by the end of your iteration, your array has stored three references to the same object (you can think of it as {x, x, x}). And since that object has changed throughout the loop (because a[i].setNum(i) is equivalent to x.setNum(i)), your last output prints the num value as 2.
You created a single Numero, so sn got incremented once, to 1. That same instance got assigned to each element of a; you saw different values for num because you printed it out at different times.
Making a static class essentially enforces the singleton design pattern. The class can only have static methods and static instance fields. Static instance fields hold the same value across all instances of the class, and you can think of it as all objects of that class sharing the same variable instead of having copies of it.
When you print a[0] in the loop, you get what you expect, but after the loop, that static ("shared") variable was changed by other objects, leaving num to be the value of 2, set by the last iteration of the for loop.
issue lies here
a[i] = x;
a[i] is pointing to X now , so whenever you call setNum method ,method belongs to X .so you will get same instance output always

What does this method return?

I have just started learning to program. I was wondering what this method returns:
public int doSomething(int size) {
int[] b = new int [size];
int c = 0;
for (int d : b) {
c = c + d;
}
return c;
}
There is nothing adding in the array and the c value is still zero.
You might confused with the line
for (int d : b) {
That is java for each loop.
Two crucial things:
int[] b = new int [size]; will initialise every element in the array to zero.
for (int d : b) notation iterates over every element in the array.
So the computation is summing the elements of the array with answer zero.
(Note that in C and C++ arrays elements are not initialised to zero and the behaviour of a similar construct in those languages would be undefined).
The cycle accumulates the sum of the values in the array b into the variable c. As an integer is set to 0 by default and you never change the values of the elements in b, the sum of size zeros is still zero and thus c is 0 when it is returned.
You have blank array - default zeros as it is int array - So currently it is returning zero. Add some numbers in array you will get their addition in returned c.
public int doSomething(int size) {
int[] b = new int [size];
b[0]=5; // add integers like this to get non zero return
b[1]=8;
.
.
b[size-1]=3;
int c = 0;
for (int d : b) {
c = c + d;
}
return c;
}

I am trying to get the mode of an input of ten numbers in java

import java.util.*;
public class main {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] quiz = new int[10];
int mean = 0,mode = 0,median,range;
Scanner scan = new Scanner(System.in);
for(int x=0;x<=9;x++){
System.out.print("Enter quiz["+(x+1)+"]:");
quiz[x]= scan.nextInt();
}
Arrays.sort(quiz);
for(int x=0;x<=9;x++){
mean = mean+quiz[x];
}
mean = mean/10;
median = (quiz[4]+quiz[5])/2;
range = quiz[9]-quiz[0];
int[] cntr = new int[10];
for(int x=0;x<=9;x++){
for(int y=0;y<=9;y++){
if (quiz[x]==quiz[y]&&x!=y){
cntr[x]++;
}
}
}
int[] sortcntr = cntr;
int ndx = 0;
Arrays.sort(sortcntr);
for(int z=0;z<=9;z++){
if(cntr[z]==sortcntr[9]){
ndx = z;
}
else
mode=0;
}
mode = quiz[ndx];
System.out.println("Mean: "+mean);
System.out.println("Median: "+median);
System.out.println("Range: "+range);
if(mode==0){
System.out.println("Mode: none");
}
else
System.out.println("Mode: "+mode);
System.out.print(sortcntr[9]);
System.out.print(cntr[9]);
System.out.println(ndx);
}
}
this is the codes that i used everything is right except for the mode. the mode variable there always returns the highest number from the number. the latter part was just for debugging and not for use. please help
The main problem of your code is that you obviously think that the line
int[] sortcntr = cntr;
creates a copy of the array cntr. However, arrays have reference semantics in Java. Thus, you simply create a second reference to the same array. If you then sort sortcntr, it applies to cntr as well since it's the same array.
To create a copy of the array:
int[] sortcntr = new int[ cntr.length ];
System.arraycopy(cntr, 0, sortcntr, 0, cntr.length);
BTW: Wouldn't it make more sense to work with floating-point numbers (double) instead of integer numbers?
for(int x=0;x<=9;x++){
for(int y=0;y<=9;y++){
The inner loop should start at x+1, otherwise you count everything twice.
Just to help you out, if you decide to more generify (As Raffaele said) the process of getting the mode of a given set of data, here is a method I developed a while ago which will even return multiple modes if there are more than one with the same occurrence. (Uses the Java 8 Stream API)
/**
* Computes the mode of the passed integers.
*
* #param args Numbers to find the mode of.
* #return Mode of the passed numbers.
*/
public static int[] mode(int... args) {
/* Create a map of integers to their frequencies */
Map<Integer, Integer> frequencies = IntStream.of(args).collect(
HashMap::new,//Indicated that this collector will result in a HashMap
(integerIntegerMap, value) -> integerIntegerMap.merge(value, 1, Maths::sum), //For each value in the arguments added, merge it with the current map and add the frequencies
(integerIntegerMap, integerIntegerMap2) -> integerIntegerMap.putAll(integerIntegerMap2) //While this is not used, it simply combines 2 HashMaps. (I think this is only used when in parallel)
);
//Here we get the maximum number of occurrences for any number, we could return the mode here; but there could be multiple modes
int maxOccurrences = frequencies.entrySet().stream().mapToInt(Map.Entry::getValue).max().getAsInt();
//Here we simply go through the entry set again, filtering out only the numbers with a frequency equal to the max, then returning them as an array
return frequencies.entrySet().stream().filter(entry -> entry.getValue() == maxOccurrences).mapToInt(Map.Entry::getKey).toArray();
}
-Thomas
Since the input is already sorted to compute range and median, you can use the following code to get the mode after a single loop and without any extra memory (live on ideone):
// this must be sorted
int[] values = {1, 1, 2, 3, 4, 5, 5, 5, 6, 7, 8, 8};
int mode = values[0];
int modeOccurrences = 1;
int occurrences = 1;
int current = values[0];
for (int i = 1; i < values.length; i++) {
int value = values[i];
if (value == current) {
occurrences++;
} else {
if (occurrences > modeOccurrences) {
mode = current;
modeOccurrences = occurrences;
}
occurrences = 1;
current = value;
}
}
if (occurrences > modeOccurrences) {
mode = current;
modeOccurrences = occurrences;
}
You can even generify this piece of code to work with plain objects instead of numerical types, provided modes can be sorted and compared (I used enums in my demo)

Swapping references in an Array [duplicate]

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 9 years ago.
Ok, I was misunderstanding the problem. After reading it a couple of times I figured out randInt is actually the method itself i am using to populate the array. So when it says to call randInt its some sort of recursive call I think. This is somehow what it should look like:
static int[] randInt(int i, int j) {
int[] temp = new int[(j - i) + 1];
for ( i = 0; i < j; i++) {
temp[i] = i + 1; // here i populate the array
}
System.out.println(Arrays.toString(temp)); // this prints [1, 2, 3, 4, 5]
for ( i = 1; i < j;i++){
swapReferences(temp[i], temp[randInt(0,i)] ); //this is some sort of recursive call that swaps the references
// btw that statement does not compile, how can i pass a method as a parameter?
}
return temp;
}
static void swapReferences(int a, int b) { //these parameters are wrong, need to be changed
//Method to swap references
}
Sorry for the confusion, but I think thats how it should be correctly.
Java is pass-by-value, so reassigning the parameters as you try to do will not work.
What you need to do is to have the array itself and two integer indices as parameters:
int randInt = generate.nextInt(j-i) + 1; //this is gonna generate a # within the range of the array (so if array is size 5, generates something 1-5)
for ( i = 1; i < j;i++){
swapReferences(temp, i, randInt); //and this is my attempt at swapping the references
randInt = generate.nextInt(i) + 1 ;
}
static void swapReferences(int[] array, int a, int b){
int x = array[a];
array[a] = array[b];
array[b] = x;
}
You can mutate parameters such as arrays passed into a method, as is being done here, but you can't reassign the parameters themselves.
You are just changing the ints that a and b are pointing to, but not what the indicies the array is pointing to. You need to change your swapReferences method to take the array as input, and something like the indicies to swap
static void swapReferences(int[] arr, int indexA, int index B){
int x = arr[indexA];
a = arr[indexB];
b = x;
arr[indexA] = a;
arr[indexB] = b;
}
or
static void swapReferences(int[] arr, int indexA, int indexB){
int x = arr[indexA];
arr[indexA] = arr[indexB];
arr[indexB] = x;
}

Categories

Resources