Array declaration to allow any int value as index - java

Is there any way to declare an int array (arr), such that
an index i can represent any number <= Integer.MAX_VALUE, which cannot be known ahead of time.
So arr[i] will never return an error, as long as the value is <= Integer.MAX_VALUE
I tried int[] arr = new int[Integer.MAX_VALUE], but that requires too much space and is not feasible.

In Java it is not possible to declare array without size. You don't need to occupy memory for all unused indices using an array. What you need is a Map, which is space efficient for your use case.
Map<Integer, Object> index = new HashMap<>();
//store
index.put(1, "Value 1");
index.put(2, "Value 2");
//retrieve
index.get(1); //returns: Value 1

Related

Java arrays objects and initializer confusion

I'm learning java and was told arrays are implemented as objects. But they show two different codes without diving into details.
First they ask us to use arrays like this, but the downside is to manually add the values:
int nums[] = new int[10];
nums[0] = 99;
nums[1] = -622;
.
.
.
Then they use this in some programs saying new is not needed because Java automatically does stuff:
int nums[] = {99, - 10, 100123, 18, - 972 ......}
If the second code is shorter and allows me to use arrays straightaway whats the point of the first code if they do the same thing but the first one require more code to input value by hand.
Let's say you were initializing an array of 1 million values, would you use the second method? No, because you would have a huge java file.
The first method is essentially allocating space:
int[] array = new int[1000000];
Creates 1 million spaces in memory with default value 0. Now if you want to initialize them, you may use a loop:
for (int i = 0; i < array.length; i++) {
array[i] = i;
}
If you wanted an array of 10 million values, you only change one number:
// Just add a 0 to 1000000
int[] array = new int[10000000]
Now, if the size of your array changes, you don't have to change the loop. But if you used the second method and wanted an array of 10 million values, you would have to add 9 million values, and 9 million commas to your java file - not scalable.
int[] array = {1, 2, 3, 4, ... 1000000};
The second method is not "scalable." It only works for small arrays where you can confidently assume that the default values of that array won't change. Otherwise, it makes A LOT more sense to use the first (more common) method.
//This is one way of declaring and initializing an array with a pre-defined size first
int nums[] = new int[10];
//This is initializing the array with a value at index 0
nums[0] = 99;
//This is initializing the array with a value at index 1 and likewise allocating rest of array index values
nums[1] = -622;
//This is another way of declaring and initializing an array directly with pre-defined values. Here if you see instead of declaring array size first, directly the values are initialized for it
int nums[] = {99, - 10, 100123, 18, - 972 ......}
It depends on the way you prefer to use the arrays, but you must remember that whenever you use "new" keyword, there is a new space or resource created every time in memory.
When you don't know the items of array at the time of array declaration, then prefer method-1,
and,
when you know the all the values of array at the time of array declaration, then go for method-2
Imagine you want to generate a series of random integers at runtime and want to store in the array:
int[] array = new int[1000000];
Random r = new Random();
for (int i = 0; i < array.length; i++)
array[i] = r.nextInt();

Iterate array if index range is in long

how to iterate through array/ list in Java. if index range is in long. As array/list only accept integer in position index.
eg
long arr[]=new long[5];
for(long i=0l;i<5l;i++)
arr[i]=i; // throw an error as arr[i] only accept integer
here arr[i] will throw an error because i is of type long and array takes input as integer in index location.
Can anyone help me out with this?
The size limit1 on arrays is Integer.MAX_VALUE so an array index that is a long makes no sense.
A List can have more than Integer.MAX_VALUE elements, but indexing it will be problematic because List::get takes an int argument.
So, you will struggle to use either arrays or lists (implemented using List) for really large data structures.
The solution ... if you really need one ... would be to implement your own List class with overload or alternative for operations that expose the size and indexing. It would not be trivial.
Another (possibly simpler) approach would be to represent your long[] as a long[][] and map the subscripts.
Finally, if you are using long as a subscript unnecessarily (i.e. the indexes don't need to go beyond Integer.MAX_VALUE), then:
long arr[] = new long[5];
for (long i = 0l; i < 5l; i++) {
arr[(int) i] = i;
}
1 - This is the theoretical maximum size. 1) You may get an OutOfMemoryError if you attempt to allocate an array that large. The JVM needs at least length * size(<type>) bytes of free contiguous storage to allocate an array of <type> of length length, where size(<type>) is the size of a primitive type or a reference. 2) In a 32 bit JVM, you are also limited by the address space dimensions. 3) In recent Hotspot JVMs, the largest array that you can allocate is actually Integer.MAX_VALUE - 5 elements: see Do Java arrays have a maximum size?
You don't need the index to be long even if your array consists of long's. Change it to
for(int i = 0; ....)
Two solutions:
Narrow the long to an integer by a cast arr[(int)i] = i;
Change the type of i to an integer and let the compiler widen it for you when it is assigned for(int i = 0; i < 5; i++) arr[i] = i;
As you cannot map all long values to a integer the compiler will not automatically narrow a variable. As you can map all integer values to a long the compiler will widen a variable automatically for you.

Get max length of row and column in java two dimensional array

What is the best and efficient way to get the maximum i, which is the number of rows and j, which is the number of columns, in a two dimensional array?
Hopefully, the time complexity can be lower than O(n) for every case. No loop here and can still find the maximum j.
For example, if I have an array like this one
[
[18,18,19,19,20,22,22,24,25,26],
[1,2,3],
[0,0,0,0]
]
Then I want to get i = 3 and j = 10 here as a result.
Can anyone help me?
You can avoid writing the loop yourself, but you can't avoid having a runtime of at least O(n), since "someone" needs to loop the source array.
Here is a possible way to do that in Java 8:
Arrays.stream(arr).map(row -> row.length).max(Integer::compare).get();
This returns the maximum length of a "row" in your 2d array:
10
Another version which avoids using the Comparator and therefore might be a bit easier to read:
Arrays.stream(arr).mapToInt(row -> row.length).max().getAsInt();
arr is supposed to be your source array.
Edit: the older version used .max(Integer::max), which is wrong and causes wrong results. See this answer for an explanation.
Assuming your array does not contain null values, you could write something like this:
private static final Comparator<int[]> lengthComparator = new Comparator<int[]> () {
#Override
public int compare(int[] o1, int[] o2) {
return o1.length - o2.length;
}
};
#Test
public void soArrayMaxLength() {
int[][] array = new int[][] {
{18,18,19,19,20, 22, 22, 24, 25,26},
{1,2,3},
{0,0,0,0}
};
int i = array.length;
Optional<int[]> longestArray =
Arrays.stream(array)
.max(lengthComparator);
int j = longestArray.isPresent() ? longestArray.get().length : 0;
System.out.println(String.format("i=%d j=%d", i, j));
}
If you happen to create a parallel stream from the array instead, you could speed up this even further.
Another option is to sort the array by length, the quicksort usually has an average complexity of O(n*log(n)) therefore this isn't faster;
int i = array.length;
Arrays.parallelSort(array, lengthComparator);
int j = array[i-1].length;
System.out.println(String.format("i=%d j=%d", i, j));
Your i is the number of rows, which is simply the length of the 2-D array (assuming you are OK with including empty/null rows in this count).
The max row length j, however, would require iterating over all the rows to find the row i having the maximum arr[i].length.
There will always be a loop1, even though the looping will be implicit in solutions that use Java 8 streams.
The complexity of getting the max number of columns is O(N) where N is the number of rows.
Implicit looping using streams probably will be less efficient than explicit looping using for.
Here's a neat solution using a for loop
int max = o;
for (int i = 0; i < array.length; i++) {
max = Math.max(max, array[i].length);
}
This works in the edge-case where array.length == 0, but if array or any array[i] is null you will get a NullPointerException. (You could modify the code to allow for that, but if the nulls are not expected, an NPE is probably a better outcome.)
1 - In theory, you could unroll the loops for all cases of array.length from 0 to Integer.MAX_VALUE, you would not need a loop. However, the code would not compile on any known Java compiler because it would exceed JVM limits on bytecode segments, etcetera. And the performance would be terrible for various reasons.
You could try this way: loop on the array and find the max length of the arrays which is in this array
byte[][] arrs = new byte[3][];
int maxLength = 0;
for (byte[] array : arrs) {
if (maxLength < array.length) {
maxLength = array.length;
}
}

Confusing regarding .get and .set in an ArrayList

(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);
}

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