Java new ArrayList clone inefficient - java

I'm getting the value of an ArrayList inside an ArrayList containing integers from a HashMap. However, I need a new copy of this data; otherwise, I will be changing data inside of the HashMap, as it returns a reference.
To overcome this, I'm creating a new instance of the ArrayList Object for each inner ArrayList. Is there a better, more efficient way to achieve this result (potentially with a different data structure?), as it is taking a very long time to complete with a large amount of data.
// Example of how I am copying the data currently
ArrayList<ArrayList<Integer>> calcRes = memo.get(n - i);
ArrayList<ArrayList<Integer>> calc = new ArrayList<>();
for (ArrayList<Integer> item : calcRes) {
calc.add(new ArrayList<>(item));
}
For a bit of context of why and how I am using this, I'm solving a problem to find all the possibilities to make stairs with N blocks.
Stairs have to descend each column by at least one. For example the stairs with six blocks would return [[5, 1], [4, 2], [3, 2, 1]]. However, for larger values N, such as 200, this takes much longer so I'm trying to cache the results inside the memo. I call the function the code above is in recursively to find more solutions. However, I don't want to change the object stored in the memo. This is because I add the previous item to the start. For example, with [3, 3] (which doesn't count as a solution), I would look at the 3 on the right and call the function I'm in again, which would give me [[2, 1]]. Then I would need to add on the 3 on the left of the original to add up to 6 blocks. This is why I am creating a new instance of the ArrayList; otherwise, the memo would be changed.

Related

How to get unique elements from an array and length of resulting array

I have an sorted array consisting elements (1,1,2,3,3,4). I want to get unique elements from this array and length of the resulting array.
Output array should consists (1,2,3,4) and size = 4.
If you are using Java 8, you can do it in the following way:
Arrays.stream(arr).distinct().toArray();
DEMO
The easiest thing to do here might be to just add your array elements to a sorted set, e.g. TreeSet:
int[] array = new int[] {1, 1, 2, 3, 3, 4};
Set<Integer> set = new TreeSet<>();
for (int num : array) {
set.add(num);
}
This option would make good sense if your code also had a need to work with a set later on at some point.
Is this for homework? If it is, please say so. I'm going to assume it is.
I would traverse the array and use a List to store values that I have already seen. If I come across a value that already appears in my List, I'll skip it. If not, I'll add it. Then I'll convert the list to an array and return it. I'm not going to write it for you because I'm assuming it's homework, but that is the basic idea.
NOTE: If performance is a concern, use a HashMap instead of a List.

Is there something faster than Collections.sort() in Java?

I made a median filter algorithm and I want to optimize it. Currently it's taking around 1 second to filter 2MM lines(a file read into an ArrayList elements) and I am trying to reduce it to less(maybe half the time?) I'm using ArrayLists for my algorithm and minimized the use of nested loops as well to avoid an increase in time, however I still can't achieve lower than 0.98 seconds tops.
Here's a code snippet that does the median filter:
//Start Filter Algorithm 2
int index=0;
while(index<filterSize){
tempElements.add(this.elements.get(index+counter)); //Add element to a temporary arraylist
index+=1;
if(index==filterSize){
outputElements.add(tempElements.get((filterSize-1)/2)); //Add median Value to output ArrayList
tempElements.clear(); //Clear temporary ArrayList
index = 0; //Reset index
counter+=1; //Counter increments by 1 to move to start on next element in elements ArrayList
}
if(elementsSize-counter <filterSize){
break; //Break if there is not enough elements for the filtering to work
}
}
What's happening is that I'm looping through the elements arraylist for the filterSize I provided. Then I add the elements to a temporary(tempElements) arraylist, sort it using Collections.sort()(this is what I want to avoid), find the median value and add it to my final output arraylist. Then I clear the tempElements arraylist and keep going through my loop until I cannot filter anymore due to the lack of elements(less than filterSize).
I'm just looking for a way to optimize it and get it faster. I tried to use a TreeSet but I cannot get the value at an index from it.
Thanks
The Java Collections.sort() implementation is as fast as it gets when it comes to sorting (dual pivot quick sort).
The problem here is not in the nitty gritty details but the fact that you are sorting at all! You only need to find the median and there are linear algorithms for that (sorting is log-linear). See selection for some inspiration. You might need to code it yourself since I don't think the java library has any public implementation available.
The other thing I suggest is to use a fixed size array (created once) instead of an ArrayList. Since you know the size of the filter beforehand that will give you a small speed boost.
Also I don't see how avoiding for loops helps performance in any way. Unless you profiled it and proved that it's the right thing to do, I would just write the most readable code possible.
Finally, TreeSet or any other kind of sorted data structure won't help either because the time complexity is log-linear for n insertions.
As an alternative to Giovanni Botta's excellent answer:
Suppose that you have an array [7, 3, 8, 4, 6, 6, 2, 4, 6] and a filterSize of 4. Then our first temp array will be [7, 3, 8, 4] and we can sort it to get [3, 4, 7, 8]. When we compute our next temporary array, we can do it in linear (or better?) time as follows:
remove 7
insert 6 in sorted position
We can repeat this for all temp arrays after the initial sort. If you're spending a lot of time sorting subarrays, this might not be a bad way to go. The trick is that it increases required storage since you need to remember the order in which to remove the entries, but that shouldn't be a big deal (I wouldn't think).

How to remove two of the same elements in two different ArrayLists?

Just started to learn Java and have a question on how I can remove the common elements from two different Arraylists?
My thought process went with:
for(int i =0; i<playerOneInputArray.size(); i++) {
if(playerOneInputArray.contains(playerTwoInputArray.get(i))){
playerOneInputArray.remove(playerTwoInputArray.get(i));
}
}
however, when I check the out put i get:
Player One! Choose your word!
hello
Player Two! Choose your word!
hellow
[h, e, l, l, o]
[h, e, l, l, o, w]
[e, l]
which I expected to only get a [w] in my new playerOneInputArray
what's going on?? :C
The problem is that you are concurrently modifying a data structure. Specifically, you are editing an ArrayList that you are iterating over.
Consider the simplified problem of removing any even numbers from an arrayList. You may consider using this approach:
public void removeEvens(ArrayList<Integer> arr){
for(int i = 0; i < arr.size(); i++){
if(arr.get(i) % 2 == 0) arr.remove(i);
}
}
But there is an issue with this approach. Consider the sample input:
1, 3, 4, 6, 7, 8
When we hit i = 2, we correctly remove 4. However, at the next iteration (i = 3), the arrayList now looks like:
1, 3, 6, 7, 8
So we are checking 7, not 6. By removing an element and moving i forward, we effectively skipped checking an element.
Your code is doing a similar operation, and suffers from a similar problem. You can both simplify your code and correct the issue by using built-in functions, such as removeAll:
playerOneInputArray.removeAll(playerTwoInputArray);
This will remove the duplicates from playerOneInputArray, but if you want to do this to playerTwoInputArray you'll have to change it a little bit, as once you've removed the duplicates from the first arrayList you can't remember which duplicates you removed. If that is the case, consider:
ArrayList<Character> duplicates = new ArrayList<Character>(playerOneInputArray);
duplicates.retainAll(playerTwoInputArray);
playerOneInputArray.removeAll(duplicates);
playerTwoInputArray.removeAll(duplicates);
Your problem is that you modify your playerOneInputArray in loop. Your code doesnt work as you expect because when you do remove(), then playerOneInputArray.size() changes. So, i recommend to use removeAll(playerTwoInputArray) instead of remove in loop.
An observation about your code:
You will encounter index out of bounds exception when the first array is longer than the second.
Also you will not check all elements between the arrays when the two arrays have different sizes because you are only using the size of the first array for the loop. Doing that creates the potential for the first issue I mentioned as well.
You need to handle these cases in some way as opposed to skipping some data or having an error.

Creating an n-dimension Array in Java during runtime

I have a String which contains arrays. Example:
"[[1, 2], [4, 5], [7, 8]]"
Now, I want to make an actual Java array out of this. I have created a function to get the dimensions and a recursive function to get each and every element of the array. Thus, I have every 1-D array created, but I would like to know if there is a way in Java to create an array of the dimension that I found during the runtime? The dimension are returned as an array. Like, for the above example the dimension is:
[3, 2]
EDIT:
Is there a way to create an actual array from this information? The dimension [3, 2] is just an example. I can have [3, 2, 4, 5] as well. Can an array be generated from this information during the runtime? I do not have this information during compile time.
There is some problem, I cannot comment on answers. So, I am editing here.
If you are doing numeric work then you should probably use a library. For example my open source library Vectorz provides proper support for multidimensional arrays / matrices (with doubles).
Then you can just do something like:
INDArray m=Arrayz.parse("[[1, 2], [4, 5], [7, 8]]");
The INDArray object encapsulates all the multidimensionality so you don't need to worry about writing big nested loops all the time, plus it provides a lot of other functions and capabilities that normal Java arrays don't have.
The main problem is that you can't reference an N dimensional array in code directly.
Fortunately java has a bit of a dirty hack that lets you have some way to work with N dimensional arrays:
Arrays are objects like every other non-primative in java.
Therefore you can have:
// Note it's Object o not Object[] o
Object o = new Object [dimensionLengh];
You can use a recursive method to build it up.
Object createMultyDimArray(int [] dimensionLengths) {
return createMultyDimArray(dimensionLengths, 0);
}
Object createMultyDimArray(int [] dimensionLengths, int depth) {
Object [] dimension = new Object[dimensionLengths[depth]];
if (depth + 1 < dimensionLengths.length) {
for (int i=0; i < dimensionLengths[depth]; i++) {
dimension[i] = createMultyDimArray(dimensionLengths, depth+1);
}
}
return dimension;
}
To use this you will need to cast from Object to Object [].
Java is type safe on arrays and mistakes can cause a ClassCastException. I would recommend you also read about how to create arrays using java reflection: http://docs.oracle.com/javase/tutorial/reflect/special/arrayInstance.html.

Array operation, adding element at the end, pushing the other elements back

I'm planning to do a small program that'll display a graph which will be updated a few times per second (maybe 100/200ms or so). The purpose is to plot over 1000 different values in the graph, somewhat like an XY plot.
When the array contains 1000 elements, I'd like to add a new element at the end, and in the process pushing all the other elements one step back. In essence, element 999 would become 998, and 998 would become 997... all the way to the first element, which would simply be thrown away. Does anyone have an example or a good algorithm for doing this, either with regular arrays, Vector, LinkedList or any other method?
My first thought would be to create a new array and copy the elements that I want to keep into the new one, throwing away say the first 100 elements. At this point, I'd add the new 100 elements at the end of the array, and keep repeating this process, but surely there must be a better way of doing this?
What you are asking about is called deque in the algorithmic world, i.e. double ended vector.
That is the class you will need.
Basically deque supports adding and removing elements from both the beginning and the end of the sequence.
EDIT Actually as I read through the documentation I was surprised to see that the sdk implementation of deque does not support direct indexing (I am used to using this structure in C++). So I kept on searching and found this answer, linking to this library, which might be of help for you.
Don't use an Array, the complexity of moving all elements is awful! The Java data structure that's best suited for this task is a Deque, I'd say.
I would keep on reusing the same array, and just restart at the beginning. To make myself more clear, suppose you have your array with elements 1..1000
int[] array = new int[1000];
...
array = {1, 2, ...., 1000 };
If you now have to add element 1001, instead of trying to have an array {2, 3, ..., 1000, 1001}, I would go for an array {1001, 2, 3, ... 1000} and just keep track at which index my array actually starts. This replaces the difficulty of moving all elements by keeping a simple counter to the begin-index. To make it easy for yourself, you can introduce a utility method
private int startIndex = 1;//0 at the start
//I assume we are in the situation with array {1001, 2, 3, ..., 1000 }
public int convertIndex( int index ){
return (index + startIndex) % 1000;
}

Categories

Resources