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);
}
}
I am passing some parameters in the URL and then I add them in a list. My list has a limit of 5 elements. So if someone adds 6th element in the URL the list would simply ignore it. So I am trying to use a counter but the logic is not working as desired. I am using While loop to achieve this. So if list size is smaller than 5 set the agencyCds otherwise just return the list.
private List<IUiIntegrationDto> generateViewIntegrationReportData(ESignatureIntegrationConfig eSignConfig) throws Exception {
int counter = 1;
if(eSignConfig.getAdditionalAgencyCds() != null ) {
List<String> combinedAgencyCds = new ArrayList<String>();
for(String agencyCd : eSignConfig.getAgencyCd()) {
combinedAgencyCds.add(agencyCd);
}
StringTokenizer token = new StringTokenizer(eSignConfig.getAdditionalAgencyCds().toString(), StringConstants.COMMA);
while(token.hasMoreTokens()) {
combinedAgencyCds.add(token.nextToken());
}
while(combinedAgencyCds.size() < 5) {
counter = counter + 1;
eSignConfig.setAgencyCd(combinedAgencyCds);
}
// eSignConfig.setAgencyCd(combinedAgencyCds);
}
List<IUiIntegrationDto> intgList = getUiIntegrationManager().retrieveUiIntegrationReportData(eSignConfig.getAgencyCd(), eSignConfig.getCreatedDays(),
eSignConfig.getLob(), eSignConfig.getTransactionStatus(), eSignConfig.getAccounts(), eSignConfig.getSortKey(), eSignConfig.getSortOrder());
return intgList;
}
I am not completely sure about this logic if it is correct or if there is nay better approach.
Thanks
Try this instead of the last while in your code:
if(combinedAgencyCds.size() <= 5) {
eSignConfig.setAgencyCd(combinedAgencyCds);
} else {
eSignConfig.setAgencyCd(combinedAgencyCds.subList(0, 5));
}
The full combined list will then be used if it is less than 5 in size. Otherwise, only the first 5 elements are used.
Edit: Or even better:
eSignConfig.setAgencyCd(combinedAgencyCds.subList(0, Math.min(5, combinedAgencyCds.size())));
Ok so let's break down what your code is currently doing.
int counter = 1;
while(combinedAgencyCds.size() < 5) {
counter = counter + 1;
eSignConfig.setAgencyCd(combinedAgencyCds);
}
This snippet of code has a couple things wrong best I can tell. First, this loop has the possibility of running forever or not at all. Because combinedAgencyCds is never being manipulated, the size won't ever change and the logic being checked in the while loop never does anything. Second, there's a more efficient loop for doing this, assuming you don't need the counter variable outside of its usage in the while loop and that is using for loops.
Example syntax is as follows:
for (int i = 0; i < combinedAgencyCds.size(); i++) {
if (i < 5) {
// Do your logic here.
}
else {
break; // Or handle extra values however you want.
}
}
Notice there is no need for the explicit declaration for a counter variable as "i" counts for you.
Now in your actual logic in the loop, I'm not sure what the setAgencyCd method does, but if it simply sets a list variable in the eSignConfig like it appears to, repeating it over and over isn't going to do anything. From what I can see in your code, you are setting a variable with the same value 5 times. If you need any more explanation just let me know and I will be happy to revise the answer.
I want to reverse the order of accessing a List inside a for()
This is my actual code
for(int i = 0; i < states.size(); i++) {
System.out.println(states.size());
states.get(i).update(true); // restore the first blockstate
states.remove(i); // remove the first blockstate from the list
}
This code works, but I would like to reverse it. I already tried other ways, like using i-- but it did not work. Can someone provide a suggestion?
I already tried other ways, like using i-- but it did not work.
Reversing a for loop consists of three steps:
Change the initial value to the last value,
Change the condition to stop after passing the initial value
Reversing the increment/decrement (i.e. ++ becomes --)
In your code this change would look as follows:
for(int i = states.size()-1 ; i >= 0 ; i--) {
System.out.println(states.size());
states.get(i).update(true); // restore the current blockstate
states.remove(i); // remove the current blockstate from the list
}
Note that the last value reached in the original loop is states.size()-1, not states.size(), so i needs to start at states.size()-1 as well.
Since your loop eventually clears out the list anyway, but does it one element at a time, you may get better clarity by deleting the call of remove(i), replacing it with states.clear() after the loop.
for(int i = states.size()-1 ; i >= 0 ; i--) {
System.out.println(states.size());
states.get(i).update(true); // restore the current blockstate
}
states.clear();
Try this:
List list = Lists.reverse(states);
for(int i = 0; i < list.size(); i++) {
System.out.println(list.size());
list.get(i).update(true); // restore the first blockstate
//list.remove(i); // remove the first blockstate from the list
}
if u want to remove element when accessing element then u have to use iterator by using simple for it is not possible... it throws concurrent modification exception
I have a Collection of objects I need to iterate over. The collection is of variable size. If the collection has more than 1 object in it, I need to perform special processing on objects 2 .. infinity.
What's the preferred method to do this? For example:
int count = 1;
for (CustomObject co : CustomObjectCollection) {
methodAll(co);
if(count > 1) {
methodSpecial(co);
}
count = count++;
}
What you have will work except for one bug: count = count++ does absolutely nothing. count = count + 1 would work, or count++, but count = count++ is a no-op.
You could also just use a boolean flag if you don't specifically need to track the count.
boolean first = true;
for (CustomObject co : CustomObjectCollection) {
methodAll(co);
if (!first) {
methodSpecial(co);
}
first = false;
}
Which to use
Which to use depends on your specific use case. Assuming that you are not looking to optimise every last op-per-second of performance then go with the option that declares your intent:
count++ is fine if you want to track or use the count outside the loop (as per Louis' answer, it is count++, not count = count++)
for(int i = 0; i < collection.size(); i++) is good as well if the collection supports a get(i) operation. This also lets you skip the first item by initialising int i to a different index. It might be used if you don't want the extra count variable hanging around outside the loop.
the above boolean first = true; (or the inverse boolean notFirst = false;) highlight that you want to treat the first and subsequent elements differently
If you have the List interface on your collection and want to skip a set number of elements, then subList is a good option
Performance
If performance is a concern, then measure it for your platform and implementation, but from general experience, from slowest to fastest, with <=20x difference between the first and last:
for each loop with iterator: slowest
for(int i = 0; i < list.size() ; i++)
declare int size = list.size() then a for(int i = 0; i < size; i++) loop
However these speed results depend on so many things that unless performance is a design goal or an identified issue go with the iterator until you have a reason to use one of the other two - the iterator is generally fast enough.
I think a better way to do this would be to work directly with the iterator like so:
Iterator<CustomObject> it = customObjectCollection.iterator();
if(it.hasNext()) { //first pass don't call methodSpecial
methodAll(it.next());
}
CustomObject customObj;
while(it.hasNext()) { //all the rest 2..infinity
customObj = it.next();
methodAll(customObj);
methodSpecial(customObj);
}
customObj = null; // for garbage collection
This way you don't have to check each iteration if this is the first run or not.
This will work with any Iterable (which is already needed for a foreach loop anyway).
Note: If this is not an ordered collection you might get different elements in the first iteration then you might expect.
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!!!