Confusing regarding .get and .set in an ArrayList - java

(I'm new at Java, coming over from Python ---)
I'm going through a tutorial and they've created a program which counts how many times a number appears in a file, then returns that number. One particular part of the program is somewhat mysterious to me and deals with the ArrayList's .get and .set (methods? functions?). The program goes like this:
// (Scan a file with the numbers, say, 2 2 3 4, and put it into data1 variable.)
// (Make An Empty ArrayList with a bunch of 0's)
Scanner data1 = null;
ArrayList<Integer> count = new ArrayList<Integer>();
Integer idx;
while(data1.hasNextInt()){
idx = data1.nextInt();
System.out.println(idx);
System.out.println(count.get(idx)+1);
count.set(idx,count.get(idx)+1);
}
//Then prints out all the values; the ArrayList contains the number of times the number n occurs in the n-th index.
My question comes at the "while" part. For concrete, let's assume data1 has the numbers 2 2 3 4. It seems that it takes idx = 2, then puts a 1 in count[2], which is reasonable. It then takes idx = 2 again (the next integer in data1) and puts a 2 in count[2], which is also reasonable. At this point, the next number in data1 makes idx = 3, but it occurs at the index 2 in the ArrayList, so it should put a 3 in count[3], which is incorrect.
So, what is .get and .set doing here? Do they pop the elements off of the list when they're done with it? Am I overlooking something?

A .get() will not automagically get elements from a List which does not have that many elements. Note: list indices, like arrays, start at 0.
If you do:
final List<Integer> = new ArrayList<Integer>();
list.get(0);
this is a runtime error (IndexOutOfBoundsException) because your list has no elements.
You have to fill it:
list.add(1); // append an element
list.get(0); // returns element at index 0
list.get(1); // IndexOutOfBoundsException!
The .set() method takes an index and a value at an argument. In a similar vein, you cannot set an element which does not already exist, except at the very end of the list:
// start from an empty list
list.set(1, 32); // IndexOutOfBoundsException!
list.set(0, 32); // OK
Final note: try not to use list[i], bracket indices are used for arrays ;) Note that arrays are not resizabe in Java. Lists (which are an implementation of a Collection), however, are. But you must append to them.
So, what this line does:
count.set(idx, count.get(idx) + 1);
is take the value at index idx, add 1 to it, and sets back this value at the same index.

In your specific case, what you are looking for is a sparse array. In Java we use a HashMap<Integer, Integer> for that purpose. You don't need any initialization with zeros, but you do need to check for null:
final Integer curr = count.get(idx);
count.put(idx, curr == null? 1 : curr+1);

You are currently using an ArrayList, which acts like an array, but makes it easier to expand it - for example, add elements to it.
What you want is the java equivalent of the python dict, a key/value storage, in java, this is called a HashMap<K,V> (docs).
Scanner data1 = null;
HashMap<Integer, Integer> count = new HashMap<Integer, Integer>();
Integer idx;
while(data1.hasNextInt()) {
idx = data1.nextInt();
System.out.println(idx);
Integer g = count.get(idx)+1;
if(g == null) {
g = 0;
}
g++;
System.out.println(g);
count.put(idx, g);
}

Related

Inspect from a specific range of an array

I have got a String array:
String[] s={"one","two","three","four"};
Now I want to inspect from first three items of that array and do not want the inspection to include the fourth item.
I am using the following code to inspect:
boolean b = Arrays.asList(s).contains("two");
Wondering if there is a solution for this!
How about
String[] newArray=new String[3];
//Copy the first three elements into newArray
System.arraycopy(s,0,newArray,0,3);
After thinking a bit I figured a solution out without the need of creating new array:
int INSPECTION_LENGTH=3;
String query="two";
public static boolean b(String[] s,int length,String query){
for(int i=0;i<length;i++){
if(s[i].equals(query)){
return true;
}
}
return false;
}
Make a sub-list of List
If using a List such as ArrayList rather than a simple array, you can produce a sub-list that is based on the original but masks away unwanted elements.
Make a List from your array.
List < String > allStrings = new ArrayList<>( Arrays.asList( array ) ) ;
Of, if you want a non-modifiable list, use List.of.
List < String > allStrings = List.of( array ) ;
Get your sub-list, calling List::subList. We must use annoying zero-based index counting. The first number is inclusively the start. The second number is exclusively the end. So getting elements 1, 2, and 3 but not 4 and more translates as ( 0 , 3 ). I might be tempted to write this as ( 1 - 1 , 4 - 1 ) meaning “ordinal one inclusive to four exclusive, subtracting one for index counting”.
List< String > firstThreeStrings = allStrings.subList( 0 , 3 ) ; // Using annoying zero-based index counting. First number is inclusive while the second is exclusive.
Be aware that any changes to the original List will show through to the sub-list. We have not created a copy, we have a created second view onto the first list’s content, hiding unwanted elements.

How to merge arrays in alternating pattern without duplicates

I'm currently learning in school but am unable to complete this part of the assignment.
An explanation with the use of for loops would be greatly appreciated.
The numbers should be added to the merged array in an alternating pattern: first from list 1, then from list 2, then list 1 again, etc. If a number in one of the arrays already appears in the merged array, then it should be ignored, and the program should alternate to the other list again. For example, if the first list begins 1 2 3 10, and the second begins 3 4 5 8, then the merged list would begin 1 3 2 4 5 10 8.
Because the number of elements in the merged array is unknown, its size should be set to the maximum possible number of elements it should contain, and after all elements which should form the merged array appear, any remaining unfilled spaces in the array should be 0. The first 0 encountered in the array should signal the end of the “actual” elements of the array, and therefore the 0s at the end of the array should not be printed by your program.
I propose to use a HashSet to remember which number you have already inserted into the array. For each number, you first check if the hash set already contains the number; if not, you add it to both the array and the set. For large inputs, this is much faster than checking the result array for each number. O(n*log(n)) or so (depending on how well the HashSet works for your input) instead of O(n^2).
#bubble
An example using a Set is very simple - however your teacher is asking for
an alternate list:
Integer[] one = new Integer[] {10,2,3,1};
Integer[] two = new Integer[] {3,8,5,4};
List<Integer> li_one = Arrays.asList(one); // First convert the arrays to a list
List<Integer> li_two = Arrays.asList(two);
Set<Integer> set = new HashSet<>();
set.addAll(li_one);
set.addAll(li_two);
System.out.println("The unique list is: " + set);
A HashSet was my first idea too, but the order of storing values depends
one hash values. The ... teacher likes to have alternating values which
I dont like to comment - because it is a really strange request.
Following code prints: merged list is: [1, 3, 2, 4, 5, 10, 8]
int[] one = new int[] {1,2,3,10};
int[] two = new int[] {3,4,5,8};
int one_len = one.length;
int two_len = two.length;
List<Integer> merged = new ArrayList<>();
int oneval,twoval;
for (int i = 0;i < one_len;i++)
{
oneval = one[i];
if (!merged.contains(oneval)) merged.add(oneval);
if (i < two_len)
{
twoval = two[i];
if (!merged.contains(twoval)) merged.add(twoval);
}
}
if (two_len > one_len)
{
for (int i = one_len; i < two_len;i++)
{
twoval = two[i];
if (!merged.contains(twoval)) merged.add(twoval);
}
}
System .out.println("merged list is: " + merged);

Pseudo code: Random Permutation

I have a pseudo code that I have translated into java code but anytime I run the code, I get an empty arraylist as a result but it is supposed to give me a random list of integers.
Here is the pseudo code:
Algorithm 1. RandPerm(N)
Input: Number of cities N
1) Let P = list of length N, (|P|=N) where pi=i
2) Let T = an empty list
3) While |P| > 0
4) Let i = UI(1,|P|)
5) Add pi to the end of T
6) Delete the ith element (pi) from P
7) End While
Output: Random tour T
Here is the java code:
public static ArrayList<Integer> RandPerm(int n)
{
ArrayList<Integer> P = new ArrayList<>(n);
ArrayList<Integer> T = new ArrayList<>();
int i;
while(P.size() > 0)
{
i = CS2004.UI(1, P.size());// generate random numbers between 1 and the size of P
T.add(P.get(i));
P.remove(P.get(i));
}
return T;
}
I don't know what I am doing wrong.
ArrayList<Integer> p = new ArrayList<>(n);
... creates an empty list with an initial capacity of n.
All this does is tell the ArrayList what size array to initialise as backing store - most of the time you achieve nothing useful by specifying this.
So your while(p.size() > 0) runs zero times, because p.size() is zero at the start.
In the pseudocode "where pi=i" suggests to me that you want to initialise the list like this:
for(int i=0;i<n;i++) {
p.add(i)
}
(I have lowercased your variable name - in Java the convention is for variables to startWithALowerCaseLetter -- only class names StartWithUpperCase. It's also the Java convention to give variables descriptive names, so cityIdentifiers perhaps)
You may want to know that, even if you fix the problem that P is always empty, there are 2 more issues with your implementation.
One is that P.remove(P.get(i)) does not necessarily remove the ith item if the list has equal value items. It scans from the beginning and removes the first occurrence of the item. See ArrayList.remove(Object obj). You should use P.remove(i) instead for the correct results.
Then the performance is O(n^2). The reason is that ArrayList remove an item by shifting all the subsequent items one slot to the left, which is an O(n) operation. To get a much better performance, you can implement your own "remove" operation by swapping the item to the end. When you generate the next random index, generate it within the range [0, beginning index of the removed items at the end). Swapping is O(1) and the overall performance is O(n). This is called Knuth Shuffle by the way.

ArrayList <Double> Understanding

I am doing a project on ArrayLists and mathematic methods such as sum, standard deviation and variance etc and I have come across this ArrayList<Double>.
public static double Sum(ArrayList<Double> list) {
double sum = 0;
for (int i = 0; i < list.size(); i++) {
sum = sum + list.get(i);
}
return sum;
}
I understand how ArrayList works but I am not exactly sure what is going on in this method, can anyone help me understand it a little better?
These are called Generics. Oracle has a great tutorial on it
Long story short, if you write List list = new ArrayList it would mean anything can be put in that list: toys, food, books. Kinda chaotic, huh? I bet what you'd rather have are boxes that contain only certain types of objects: a box for toys, another one for food and one more for books. That's generally what generics allow you to do. By writing List<Book> list = new ArrayList<>(), you're saying that this list can contain only books. If you try to put something else in there, you will get an error.
To sum up, in your case, method sum takes ArrayList<Double> - a list that can contain only Double objects. You can be sure that all of the elements are of that type, so you needn't check.
Look at this: ArrayList<Double> list = new ArrayList<Double>(); it creates a list that can only contain double values. A double is a variable type that can contain whole numbers and decimal numbers. So creating a list like this only allows the program to add numbers to the list: list.add(4.3);
When you call this method, you must pass an ArrayList<Double> object to it: Sum(List); Then it takes the list and adds every element of that list together into a variable called sum. After it has done that, it will return that sum. return sum;.
Here's how it does that:
for (int i = 0; i < list.size(); i++) {
sum = sum + list.get(i);
}
Its basic syntax is for(initialization; condition; iteration). When first called it will execute the initialization, then it will continue to repeat as long as the condition is true, and every time it repeats it will execute the iteration.
This specific one creates a variable called i and assigns it the value 0 for its initialization. Then for its condition it does i < list.size(), meaning that it will repeat as long as the integer value contained in i is less then the number of elements in the ArrayList. Finally, for its iteration it does i++, which will make the integer contained in i one value larger every time the thread loops.
So our i will get one value larger every time the loop iterates. Inside the loop we have sum = sum + list.get(i);. This takes the double (decimal) variable sum and adds to its current value whatever value is contained in the i (remember i has a number value) element of the ArrayList.
Click this link to learn more about for loops: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/for.html
So if the ArrayList contained the values {2, 4, 1, 5} and i contained the value 1, then calling sum = sum + list.get(i); would add the value 4 to the the value contained in sum. If i equaled 0 and we called sum = sum + list.get(i), than sum's value would be increased by 2, and it goes on like that.
These are called indexes. Indexes are numbers used to access objects in arrays or array lists. If I had an array that looked like this: int array[] = {4, 2, 5, 3}; then 4's index would be 0, 2's index would be 1, 5's index would be 2, and 3's index would be 3.
This image can give you a better understanding of indexes:

Writing to arrays in Java

I have an array of integers and I want to save pairs of integers using the index of the array as one of the indexes and the value as the other integer.
For example, if I wanted to save the pair: 2, 4. I could do: dependencias[2] = 4 (or dependencias[4] = 2.
It should be fairly simple, right? But I can't do it! I keep getting an out of bounds error. This is my code:
int recursoA, recursoB;
dependencias = new int[numberDependencias];
/* I tried setting them all to 0, to see if that was the problem.
* It didn't do anything, as I expected. */
for (int i = 0; i < numberDependencias; i++){
dependencias[i] = 0;
}
int recursoA, recursoB,cont = 0;
while (numberDependencias > 0){
System.out.println("Introduce el primer recurso");
recursoA = Integer.parseInt(br.readLine());
if ((recursoA > 1) && (recursoA <= recursos)){
System.out.println("Introduce el segundo recurso");
recursoB = Integer.parseInt(br.readLine());
dependencias[recursoA] = recursoB; // This is the problem, apparently.
numberDependencias--;
}
Sorry the variables are in Spanish, but hopefully you'll see what I'm talking about. I can't translate it right now.
The integer you're reading-in (recursoA) has to be greater than 1 and less than "recursos". The problem, is that "recursos" is probably greater than "numberDependencias"...which is the max size of your array.
Either alter this line to make sure that recursoA is always less then numberDependencias.
if ((recursoA > 1) && (recursoA < numberDependencias)){
Or, define your array size to be "recursos".
dependencias = new int[recursos];
A Java array has fixed bounds. If you declare it like this:
a = new int[3];
then you can only assign values to a[0], a[1] and a[2]. What you want here is not an array but a Map.
Map<Integer, Integer> dependencias = new HashMap<Integer, Integer>();
dependencias.put(4000, 2000);
dependencias.get(4000) // returns 2000
I suspect the error is being caused by the line:
if ((recursoA > 1) && (recursoA <= recursos)){
What value is recursos being set to? If it is above numberDependencias then an out of bounds error would make sense. Additionally, the open brace at the end of that line doesn't seem to be being closed. This will certainly cause an error!
What values are you trying to introduce for recursoA?
I think you should check if this value is between 0 and numberDependencias-1. Keep in mind that arrays begin at 0, so if you create an array with 4 positions, you can assign values to array[0] ... array[3].
Well I believe what you're saying that you are creating an array that's the size of the number of these "pairs" you have. However, this will give you out of range errors if you have a number larger then the number of pairs, you will get errors. If this is unclear, say you have 2 pairs, (9, 3) and (3, 4), and you try to save them in your array as dependencias[3] = 9 and dependencias[4] = 3. Your going to get errors as dependencias is not large enough for those values to be used as indexes.
To fix this use a Map, which is made like this,
Map<Integer, Integer> dependencias = new HashMap<Integer, Integer>();
then you can add things to your map, like so:
dependencias.put(someInteger1, someInteger2);
Finally you can call back that pair using:
dependencias.get(someInteger1); //this will return someInteger2
Your problem is right here numberDependencias > 0, because you initialze an array with number of elements starting at 0. When you start to fill at numberDependencias, you're try to put in an element out of the arrays size. Try numberDependencias-1 > 0 and use array[numberDependencias] instead of recursoA, excepting you want to initialize your array with recursoA.
Instead of an array I would prefer java.util.HashMap where you can easily put key-value pairs into, besides that you don't need to worry about initializing your size or out of bounds errors.

Categories