ArrayList string loop mess up strings - java

I've got an ArrayList called PhotoArrayList. It contains strings like "picture1.jpg, picture2.png, picture3.gif etc." There is like 50 or 60 strings in this ArrayList. I need to add path of their folder in the beginning like "mnt/sdcard0/Pictures/picture1.jpg etc." So, I'm using following code
Integer PhotoFileAmount = PhotoArray.length; //PhotoArray and PhotoArrayList are same
for(int i=0; i < PhotoFileAmount; i++){
String PhotoFileAndPath = (PhotoFolder + '/' + PhotoArrayList.get(i));
PhotoArrayList.remove(PhotoArrayList.get(i));
PhotoArrayList.add(PhotoFileAndPath);
}
But I'm getting a strange result. The beginning of PhotoArrayList is unchanged while it's middle part is okay and last part gets the path twitce. Like "picture1.jpg, mnt/sdcard0/Pictures/picture2.png, mnt/sdcard0/Pictures/mnt/sdcard0/Pictures/picture3.gif

If you want to change elements of a ArrayList, use the set method to assign a new value to the element at a given position:
int PhotoFileAmount = PhotoArray.length; // use int here to avoid unnecessary boxing / unboxing
for(int i=0; i < PhotoFileAmount; i++){
String PhotoFileAndPath = (PhotoFolder + '/' + PhotoArrayList.get(i));
PhotoArrayList.set(i, PhotoFileAndPath);
}
If you use remove and add you not only change the indices of the elements in the list; even if you make it work it's very inefficient, since all remaining elements in the list have to be moved every time remove is called.

ArrayList.add(E Object) adds the Object at the at the end of the list.
You are currently removing an item from where ever it is in the list, then adding a new version at the end of the list. As i approaches PhotoFileAmount your .get(i) statement is going to start retrieving the revised objects that you have added at the end.

Related

looping through List and removing element skipps certain elements

If have a workflow that removes elements of a List by a certain criteria. However certain items are skipped? Why is this happening?
List<Integer> listWithAge = new ArrayList<>();
int randomNumber = 100;
for (int i = 0; i < randomNumber; i++) {
listWithAge.add(i);
}
// this is my loop
for (int i = 0; i < listWithAge.size(); i++) {
System.out.println(i);
if ((listWithAge.get(i) % 3) == 2) listWithAge.remove(i);
}
Above code is my loop. I replaced my condition with something simpler. If I run this code my second loop only runs for 67 turns instead of 100.
It is problematic to iterate over a list and remove elements while iterating over it.
If you think about how the computer has to reconcile it, it makes sense...
Here's a thought experiment for you to go through.
If you have a list that is size 10 and you want to remove elements 1, 5, and 9 then you would think maybe the following would work:
List<String> listOfThings = ...some list with 10 things in it...;
list.remove(0);
list.remove(4);
list.remove(8);
However, after the first remove command, the list is only size 9.. Then after the second command, it's size has become 8. At this point, it hardly even makes sense to do list.remove(8) anymore because you're looking at an 8-element list and the largest index is 7.
You can also see now that the 2nd command didn't even remove the element now that you wanted.
If you want to keep this style of "remove as I go" syntax, the more appropriate way is to use Iterators. Here's an SO that talks about it and shows you the syntax you would need (see the question). It's easy to read up on elsewhere too.
How Iterator's remove method actually remove an object
Skipping a value would be the result of your list getting out of sync with your loop index because the list is reduced in size. This causes you to hop over some locations since the reduction in size affects future locations that have not been reached.
So the first thing you could do is simply correct the synchronization by decrementing i when you remove a value from the list. This will keep index at the same spot as the list shifts "left" caused by the removal.
for (int i = 0; i < listWithAge.size(); i++) {
if ((listWithAge.get(i) % 3) == 2) listWithAge.remove(i--);
}
The other option is to loop thru the list backwards.
for (int i = listWithAge.size()-1; i >= 0; i--) {
if ((listWithAge.get(i) % 3) == 2) {
listWithAge.remove(i);
}
}
This way, no values should be skipped since the removing of the element does affect the loop index's future positions relative to the changing size of the list.
But the best way would be to use an iterator as has already been mentioned by
Atmas
As a side note, I recommend you always use blocks {} even for single statements as I did above in the if block. It will save you some serious debugging time in the future when you decide you need to add additional statements and then wonder why things are no longer working.
And deleting like this from a list is very expensive, especially for large lists. I would suggest that if you don't have duplicate values, you use a Set. Otherwise, instead of deleting matching values, add the non-matching to a second list.
List<Integer> listWithAge = new ArrayList<>();
int randomNumber = 100;
for (int i = 0; i < randomNumber; i++) {
listWithAge.add(i);
}
// this is my loop
List<Integer> itemsToBeDeleted = new ArrayList<>();
for (int i = 0; i < listWithAge.size(); i++) {
System.out.println(i);
if ((listWithAge.get(i) % 3) == 2) {
itemsToBeDeleted.add(i);
}
//delete all outside the loop
//deleting inside the loop messes the indexing of the array
listWithAge.removeAll(itemsToBeDeleted);

How can I properly return ArrayList<Object> from recursive method without repeated values?

I need a recursive solution which returns any combination of n subset from k set (in mathematical sense). I have an ArrayList and I want return any possible n-size subsets from recursive method. Order doesn't matter.
So if I have set of employees {Jim, Tom, Ann, John} and want 2 of them I should get:
{Jim Tom}{Jim Ann}{Jim John}{Tom Ann}{Tom John}{Ann John}
I found this https://stackoverflow.com/a/16256122/10929764
but it only prints out result. I modified it a bit to add any combination to ArrayList and return it, but it doesn't work properly.
Here is a code:
public ArrayList<Employee[]> combinationsOfEmployee(ArrayList<Employee>sourceList, int selected, int startIndex, Employee[] result, ArrayList<Employee[]>allResults){
if(selected == 0){
for(int i=0; i<result.length; i++){
System.out.print(result[i].getLastName() + " ");
}
System.out.println("");
allResults.add(result);
return allResults;
}
for(int i=startIndex; i<=sourceList.size() - selected; i++){
result[result.length - selected] = sourceList.get(i);
combinationsOfEmployee(sourceList, selected - 1, i + 1, result, allResults);
}
return allResults;
}
It prints out properly all combinations, but adds the same values all the time to ArrayList. So allResults is
{Ann, John}{Ann, John}{Ann, John}{Ann, John}{Ann, John}{Ann, John}
instead of:
{Jim Tom}{Jim Ann}{Jim John}{Tom Ann}{Tom John}{Ann John}
You are wondering why it prints it fine while the returned list seems to have the exact same array at each position.
That's because it's the exact same array (same reference to the same object). Since in your solution you are using only one array, when you call allResults.add(result), you add the reference to your only array in the list. Then you keep modifying it when you look for the other combinations. That's why your list only contains the last combination found.
The solution to this is to add a new array each time you find a combination by adding a copy of your current array to your list. Simply replace
allResults.add(result);
by
allResults.add(Arrays.copyOf(result, result.length));
That way, every element of your list points to a different array.

Java - removing an element in list while iterating it with a for index loop

I know that removing an element from a list while iterating it is not recommended.
You better use iterator.remove(), java streams, or copy the remove to an external list.
But this simple code just works:
static List<Integer> list = new ArrayList<Integer>();
...
private static void removeForI() {
for (int i = 0; i < 10; i++) {
if (i == 3) {
list.remove(i);
continue;
}
System.out.println(i);
}
}
Is it safe to use it?
You need to think about how list.remove(index) works.
When remove(idx) gets called, the element at idx index gets deleted and all the next elements gets shifted to left.
So, suppose you have a list containing 2, 3, 3, 4, 5. Now you want to remove all the 3s from this list. But if you use your current approach, it will remove only the first occurrence of 3. Because after removing 1st occurrence of 3 which is at position 1 your contents will get shifted to left and will be like this 2, 3, 4, 5. But now your for loop will increment the current index to 2 which contains 4 and not 3.
That is why it is not advised to remove items while iterating, Because index of items gets changed after each removal.
Edit: Also if you are using a constant value in loop break condition like in above example i<10; you might get ArrayIndexOutOfBounds exception.
Even though it works under the condition people have pointed out, I would only use it temporarily and change it to:
private static void removeForI() {
list.remove(3);
list.foreach(System.out::println);
}
There is no need to check if i==3, simply remove it before the for loop.
It looks like that loop will be having a different conditional later on as otherwise you can simply do as JoschJava stated.
However if you truly want to iterate through all of your elements and remove a specific one during the loop, you may want to shift the index backwards afterwards. If that is the case, I would add this at the end of your conditional body:
i -= 1;
It isn't safe at all. When you know you might temper the list during iteration, convert your list object into Iterator object then use its methods : hasNext, next, remove...

Incompatible data types in Java, array and integer

I'm trying to get a program so that it loops and adds up the sum of an array. My code appears to be working, with the exception that it states that the text[j] in adding = adding + text[j] is an incompatible type (I'm assuming data type). Earlier in the code, I have int adding = 0;. This is the erroneous code:
for (int j=0;j<=total;j++){
adding = adding + text[j];
System.out.println(text[j]);
}
where total is the limiting factor. If I put:
for (int j=0;j<= total;j++){
adding = adding + j;
System.out.println(text[j]);
}
the program compiles but gives 45, which is incorrect.
Why is this happening? Thanks!
The answer actually turned out to be outside the code given. I had set my array to be a String, not an int as it should have been.
If your text[] is String[] or char[] as the name suggests then I believe you are trying to update text[] elements with suffix j or adding, which you can write as:
If it is char[] then write
text[j] = (char)(adding + (int)text[j]);
If it is String[] then write
text[j]= text[j]+adding;
as required. It all depends on what is the data type of text[] and what are you trying to achieve?
Also as suggested in one of the answers, if total is length of the array, then change the comparison to < to avoind ArrayIndexOutOfBoundsException
Your second example, adds j into adding but prints text[j] value, which is nothing to do with the addition of adding and j.

Checking if ArrayList element exists or not

I'll try to explain this as best I can. I have an ArrayList of String's. I am trying to implement server-side paging for a webapp. I am restricted to the number of items per page (6 in this case) which are read from this ArrayList. The ArrayList is, lets say, the entire catalog, and each page will take a section of it to populate the page. I can get this working just fine when there are enough elements to fill the particular page, its when we hit the end of the ArrayList where there will be less than 6 items remaining for that pages segment. How can I check if the ArrayList is on its last element, or if the next one doesn't exist? I have the following code (in pseudo-ish code):
int enterArrayListAtElement = (numberOfItemsPerPage * (requestedPageNumber - 1));
for (int i = 0; i < numberOfItemsPerPage; i++) {
if (!completeCatalog.get(enterArrayListAtElement + i).isEmpty() {
completeCatalog.get(enterArrayListAtElement + i);
}
}
The if in the code is the problem. Any suggestions will be greatly appreciated.
Thanks.
It sounds like you want:
if (enterArrayListAtElement + i < completeCatalog.size())
That will stop you from trying to fetch values beyond the end of the list.
If that's the case, you may want to change the bounds of the for loop to something like:
int actualCount = Math.min(numberOfItemsPerPage,
completeCatalog.size() - enterArrayListAtElement);
for (int i = 0; i < actualCount; i++) {
// Stuff
}
(You may find this somewhat easier to format if you use shorter names, e.g. firstIndex instead of enterArrayListAtElement and pageSize instead of numberOfItemsPerPage.)
Can't you just get
completeCatalog.size()
and compare it to i? i.e to answer the question "is there an ith element" you say
if (i<completeCatalog.size())
You just need to add a second expression to look whether the end of the list was reached already:
int enterArrayListAtElement = (numberOfItemsPerPage * (requestedPageNumber - 1));
for (int i = 0; i < numberOfItemsPerPage; i++) {
if (enterArrayListAtElement + i < completeCatalog.size() && !completeCatalog.get(enterArrayListAtElement + i).isEmpty() {
completeCatalog.get(enterArrayListAtElement + i);
}
}
An ArrayList has the method of size(), which returns the number of elements within the List.
Therefore, you can use this within the if statement to check you've not went too far.
For example,
if(enterArrayListAtElement + i < completeCatalog.size()) {
...
}

Categories