for(int i = 0; i < points.size(); i = i+lines) {
points.remove(i);
}
The idea here is that a user can either remove every other space or every third space or every fourth space .. And so forth, of an array list by entering an int "line" that will skip the spaces. However, I realize the list gets smaller each time messing with the skip value. How do I account for this? I'm using the ArrayList library from java so don't have the option of just adding a method in the array list class. Any help would be greatly appreciated.
I've perfomed a benchmark of all the answers proposed to this question so far.
For an ArrayList with ~100K elements (each a string), the results are as follows:
removeUsingRemoveAll took 15018 milliseconds (sleepToken)
removeUsingIter took 216 milliseconds (Arvind Kumar Avinash)
removeFromEnd took 94 milliseconds (WJS)
Removing an element from an ArrayList is an Θ(n) operation, as it has to shift all remaining elements in the array to the left (i.e. it's slow!). WJS's suggestion of removing elements from the end of the list first, appears to be the fastest (inplace) method proposed so far.
However, for this problem, I'd highly suggest considering alternative data structures such as a LinkedList, which is designed to make removing (or adding) elements in the middle of the list fast. Another alternative, if you have sufficient memory, is to build up the results in a separate list rather than trying to modify the list inplace:
removeUsingIterLinked took 12 milliseconds
removeUsingSecondList took 3 milliseconds (sleepToken with WJS's comment)
Use an Iterator with a counter e.g. the following code will remove every other (i.e. every 2nd) element (starting with index, 0):
Iterator<Point> itr = points.iterator();
int i = 0;
while(itr.hasNext()) {
itr.next();
if(i % 2 == 0) {
itr.remove();
}
i++;
}
Here, I've used i as a counter.
Similarly, you can use the condition, i % 3 == 0 to remove every 3rd element (starting with index, 0).
Here is a different approach. Simply start from the end and remove in reverse. That way you won't mess up the index synchronization. To guarantee that removal starts with the second item from the front, ensure you start with the last odd index to begin with. That would be list.size()&~1 - 1. If size is 10, you will start with 9. If size is 11 you will start with 9
List<Integer> list = IntStream.rangeClosed(1,11)
.boxed().collect(Collectors.toList());
for(int i = (list.size()&~1)-1; i>=0; i-=2) {
list.remove(i);
}
System.out.println(list);
Prints
[1, 3, 5, 7, 9, 11]
You could add them to a new ArrayList and then remove all elements after iterating.
You could set count to remove every countth element.
import java.util.ArrayList;
public class Test {
static ArrayList<String> test = new ArrayList<String>();
public static void main(String[] args) {
test.add("a");
test.add("b");
test.add("c");
test.add("d");
test.add("e");
ArrayList<String> toRemove = new ArrayList<String>();
int count = 2;
for (int i = 0; i < test.size(); i++) {
if (i % count == 0) {
toRemove.add(test.get(i));
}
}
test.removeAll(toRemove);
System.out.print(test);
}
}
Related
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);
Basically, i have an ArrayList titled "recentContacts", and i have limited the number of entries to 10.
Now im trying to get the ArrayList to replace all the entries from the first index, after the list is full.
Here is some code to demonstrate...
// Limits number of entries to 10
if (recentContacts.size() < 10)
{
// Adds the model
recentContacts.add(contactsModel);
}
else
{
// Replaces model from the 1st index and then 2nd and 3rd etc...
// Until the entries reach the limit of 10 again...
// Repeats
}
Note: The if statement above is just a simple example, and might not be the correct way to solve the problem.
What would be the most simplest way of achieving this? Thanks!
You have to maintain the index of the next element that would be replaced.
Actually you can use that index even before the ArrayList is "full".
For example :
int index = 0; // initialize the index to 0 when the ArrayList is empty
...
recentContacts.add(index,contactsModel);
index = (index + 1) % 10; // once index reaches 9, it will go back to 0
...
this is part of a homework assignment that isn't working properly. I was given this class of object to use:
private static class Segment {
int start, end;
Segment(int start, int end) {
this.start = start;
this.end = end;
}
}
So, as you can see, a segment has a start and an end. Think of it as a segment of time. I want to loop through an ArrayList of Segments and if an integer falls within that segment, inclusive, the segment will be removed from the list. This is my loop:
for (int i=0; i < segmentList.size(); ++i) {
if (segmentList.get(i).start <= minEnd && minEnd <= segmentList.get(i).end) {
segmentList.remove(segmentList.get(i));
}
}
The issue I am having is that it doesn't remove all the segments. Take these segments:
4,7
1,3
2,5
5,6
Another method looks at ends of segments and chooses the smallest. It correctly figures minEnd is 3, it removes the 1,3 segment, but leaves 2,5. The correct output should be that 1,3 and 2,5 are removed in first pass. Then next pass minEnd will be 6. Thanks in advance for any help you can provide.
as already given in comments, while iterating with index, removing elements will shrink the list so you wont get the desired result.
You could use an iterator to remove elements from list
Iterator<Segment> it = segmentList.iterator();
while (it.hasNext()) {
Segment seg = it.next();
if (seg.start <= minEnd && minEnd <= seg.end) {
it.remove();
}
}
Output
[Segment:: start 4 end 7, Segment:: start 5 end 6]
Java-8 streams
List<Segment> segments = segmentList.stream().filter(seg -> seg.start <= minEnd && minEnd <= seg.end).collect(Collectors.toList());
Output
[Segment:: start 4 end 7, Segment:: start 5 end 6]
Your code is not going to work since you are changing the size of the collection while modifying it, this is not good since expose the code at runtime to exceptions related with trying to go beyond the range in the list.
the way to go can be:
use a temporal list, add to it the eleemnts you want to remove and then when the search is over remove the refeferences from the orginal list..
List#removeAll(...) willl do the trick.
https://docs.oracle.com/javase/8/docs/api/java/util/List.html#removeAll-java.util.Collection-
I got a weird problem.
I thought this would cost me few minutes, but I am struggling for few hours now...
Here is what I got:
for (int i = 0; i < size; i++){
if (data.get(i).getCaption().contains("_Hardi")){
data.remove(i);
}
}
The data is the ArrayList.
In the ArrayList I got some strings (total 14 or so), and 9 of them, got the name _Hardi in it.
And with the code above I want to remove them.
If I replace data.remove(i); with a System.out.println then it prints out something 9 times, what is good, because _Hardi is in the ArrayList 9 times.
But when I use data.remove(i); then it doesn't remove all 9, but only a few.
I did some tests and I also saw this:
When I rename the Strings to:
Hardi1
Hardi2
Hardi3
Hardi4
Hardi5
Hardi6
Then it removes only the on-even numbers (1, 3, 5 and so on).
He is skipping 1 all the time, but can't figure out why.
How to fix this? Or maybe another way to remove them?
The Problem here is you are iterating from 0 to size and inside the loop you are deleting items. Deleting the items will reduce the size of the list which will fail when you try to access the indexes which are greater than the effective size(the size after the deleted items).
There are two approaches to do this.
Delete using iterator if you do not want to deal with index.
for (Iterator<Object> it = data.iterator(); it.hasNext();) {
if (it.next().getCaption().contains("_Hardi")) {
it.remove();
}
}
Else, delete from the end.
for (int i = size-1; i >= 0; i--){
if (data.get(i).getCaption().contains("_Hardi")){
data.remove(i);
}
}
You shouldn't remove items from a List while you iterate over it. Instead, use Iterator.remove() like:
for (Iterator<Object> it = list.iterator(); it.hasNext();) {
if ( condition is true ) {
it.remove();
}
}
Every time you remove an item, you are changing the index of the one in front of it (so when you delete list[1], list[2] becomes list[1], hence the skip.
Here's a really easy way around it: (count down instead of up)
for(int i = list.size() - 1; i>=0; i--)
{
if(condition...)
list.remove(i);
}
Its because when you remove an element from a list, the list's elements move up. So if you remove first element ie at index 0 the element at index 1 will be shifted to index 0 but your loop counter will keep increasing in every iteration. so instead you of getting the updated 0th index element you get 1st index element. So just decrease the counter by one everytime you remove an element from your list.
You can use the below code to make it work fine :
for (int i = 0; i < data.size(); i++){
if (data.get(i).getCaption().contains("_Hardi")){
data.remove(i);
i--;
}
}
It makes perfect sense if you think it through. Say you have a list [A, B, C]. The first pass through the loop, i == 0. You see element A and then remove it, so the list is now [B, C], with element 0 being B. Now you increment i at the end of the loop, so you're looking at list[1] which is C.
One solution is to decrement i whenever you remove an item, so that it "canceles out" the subsequent increment. A better solution, as matt b points out above, is to use an Iterator<T> which has a built-in remove() function.
Speaking generally, it's a good idea, when facing a problem like this, to bring out a piece of paper and pretend you're the computer -- go through each step of the loop, writing down all of the variables as you go. That would have made the "skipping" clear.
I don't understand why this solution is the best for most of the people.
for (Iterator<Object> it = data.iterator(); it.hasNext();) {
if (it.next().getCaption().contains("_Hardi")) {
it.remove();
}
}
Third argument is empty, because have been moved to next line. Moreover it.next() not only increment loop's variable but also is using to get data. For me use for loop is misleading. Why you don't using while?
Iterator<Object> it = data.iterator();
while (it.hasNext()) {
Object obj = it.next();
if (obj.getCaption().contains("_Hardi")) {
it.remove();
}
}
Because your index isn't good anymore once you delete a value
Moreover you won't be able to go to size since if you remove one element, the size as changed.
You may use an iterator to achieve that.
for (Iterator<Object> it = data.iterator(); it.hasNext();) {
if ( it.getCaption().contains("_Hardi")) {
it.remove(); // performance is low O(n)
}
}
If your remove operation is required much on list. Its better you use LinkedList which gives better performance Big O(1) (roughly).
Where in ArrayList performance is O(n) (roughly) . So impact is very high on remove operation.
It is late but it might work for someone.
Iterator<YourObject> itr = yourList.iterator();
// remove the objects from list
while (itr.hasNext())
{
YourObject object = itr.next();
if (Your Statement) // id == 0
{
itr.remove();
}
}
In addition to the existing answers, you can use a regular while loop with a conditional increment:
int i = 0;
while (i < data.size()) {
if (data.get(i).getCaption().contains("_Hardi"))
data.remove(i);
else i++;
}
Note that data.size() must be called every time in the loop condition, otherwise you'll end up with an IndexOutOfBoundsException, since every item removed alters your list's original size.
This happens because by deleting the elements you modify the index of an ArrayList.
import java.util.ArrayList;
public class IteratorSample {
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<Integer> al = new ArrayList<Integer>();
al.add(1);
al.add(2);
al.add(3);
al.add(4);
System.out.println("before removal!!");
displayList(al);
for(int i = al.size()-1; i >= 0; i--){
if(al.get(i)==4){
al.remove(i);
}
}
System.out.println("after removal!!");
displayList(al);
}
private static void displayList(ArrayList<Integer> al) {
for(int a:al){
System.out.println(a);
}
}
}
output:
before removal!!
1
2
3
4
after removal!!
1
2
3
There is an easier way to solve this problem without creating a new iterator object. Here is the concept. Suppose your arrayList contains a list of names:
names = [James, Marshall, Susie, Audrey, Matt, Carl];
To remove everything from Susie forward, simply get the index of Susie and assign it to a new variable:
int location = names.indexOf(Susie);//index equals 2
Now that you have the index, tell java to count the number of times you want to remove values from the arrayList:
for (int i = 0; i < 3; i++) { //remove Susie through Carl
names.remove(names.get(location));//remove the value at index 2
}
Every time the loop value runs, the arrayList is reduced in length. Since you have set an index value and are counting the number of times to remove values, you're all set. Here is an example of output after each pass through:
[2]
names = [James, Marshall, Susie, Audrey, Matt, Carl];//first pass to get index and i = 0
[2]
names = [James, Marshall, Audrey, Matt, Carl];//after first pass arrayList decreased and Audrey is now at index 2 and i = 1
[2]
names = [James, Marshall, Matt, Carl];//Matt is now at index 2 and i = 2
[2]
names = [James, Marshall, Carl];//Carl is now at index 3 and i = 3
names = [James, Marshall,]; //for loop ends
Here is a snippet of what your final method may look like:
public void remove_user(String name) {
int location = names.indexOf(name); //assign the int value of name to location
if (names.remove(name)==true) {
for (int i = 0; i < 7; i++) {
names.remove(names.get(location));
}//end if
print(name + " is no longer in the Group.");
}//end method
This is a common problem while using Arraylists and it happens due to the fact that the length (size) of an Arraylist can change. While deleting, the size changes too; so after the first iteration, your code goes haywire. Best advice is either to use Iterator or to loop from the back, I'll recommend the backword loop though because I think it's less complex and it still works fine with numerous elements:
//Let's decrement!
for(int i = size-1; i >= 0; i--){
if (data.get(i).getCaption().contains("_Hardi")){
data.remove(i);
}
}
Still your old code, only looped differently!
I hope this helps...
Merry coding!!!
Hi
this code will return indexoutofboundsException and really I don't know why?
I want to remove those objects from pointlist which are as the same as an object in the list.
public void listOfExternalPoints(List<Point> list) {
System.out.println(list.size());
System.out.println(pointList.size());
int n = pointList.size();
for (int i = pointList.size() - 1; i >= 0; i--) {
for (int j = 0; j < list.size(); j++) {
if (pointList.get(i)==(list.get(j))) {
pointList.remove(i);
n--;
}
}
}
}
Also the out put of println will be :
54
62
Also the exception:
Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 60, Size: 60
at java.util.ArrayList.RangeCheck(ArrayList.java:547)
at java.util.ArrayList.get(ArrayList.java:322)
at ConvexHull.BlindVersion.listOfExternalPoints(BlindVersion.java:83)
thanks.
hey, you removed some elements from the list. So the list is smaller than it was at the beginning of the loop.
I suggest you to use:
pointList.removeAll(list)
Or an iterator.
When you do pointList.remove(i), you should break from the inner loop. Otherwise, it will try to index pointList.get(i), which you just removed, again on the next iteration of the loop, which is why are you getting the exception.
When arrayLists remove elements, that element is taken out, and all elements after it gets shifted down. So if you remove index 3 and there are only 4 elements, the new arrayList only has size 3 and you try to get index 3, which is out of bounds.
EDIT: A better way to do this is:
for(Point p : list) {
pointList.remove(p);
}
It will have the same efficiency, but more correct, I think. Remember that == compares references for the same object. Where as the remove method uses .equals to check for equality, which is what I assume you want.
pointList.remove(i);
This will decrease your pointList size. Hope this helps.
Removing the object from pointList will reduce its size. Therefore, in one iteration of the "for j" block, you may be removing two elements of PointList, shifting all other elements to the left. However, in the next iteration "i" will refer to an out of bounds location (60).
The problem is with the order of loop evaluation. You are only evaluating the length of pointList once, and never checking it again.
If you remove the last item from pointList, and you have not reached the end of list, then you will attempt to get() same item from pointList again and you will be reading off the end of the list, causing the exception. This is what shoebox639 noticed; if you break the inner loop after removing something, the decrement in the outer loop will fix the issue.
Because of the order of iteration, it is impossible to remove two elements from the same run through the loop- you're only considering the end of the list, so nothing beyond the current point in pointList is candidate for removal. If you were to remove two elements at once, it would be possible to shorten the list to a degree that the next i is off the list, but that can't happen here. Watch out for it in other, similar loops, though.
You may remove more then one element of the pointList in every run of the first loop (over the pointList).
Put a breackpoint in the line
pointList.remove(i);
and step through your code with the debugger and you will see it.
Instead of iterating over your list with an integer, use the for each construct supported by the Collections interface.
public void listOfExternalPoints(List<Point> list) {
for (Point pointListEntry : pointList) {
for (Point listEntry : list) {
if (pointListEntry == listEntry) {
pointList.remove(pointListEntry);
}
}
}
}
I haven't debugged this, but it looks right to me.