This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 5 years ago.
I have the following code:
// Creates ArrayList with integers 0-9
ArrayList<Integer> intKeys = new ArrayList<Integer>();
for (int x = 0; x < 10; x++) {
intKeys.add(x);
}
// Creates iterator with integers 0-9
Iterator<Integer> allKeys = intKeys.iterator();
// Loops 10 times, each time obtaining a key to remove from the ArrayList
for (int x = 0; x < 10; x++) {
Integer key = allKeys.next();
intKeys.remove(key);
}
I understand that ConcurrentModificationException is thrown if an element of a collection is removed while the collection is being looped over, such as:
for (String key : someCollection) {
someCollection.remove(key);
}
but right now I'm looping over nothing - just an arbitrary number of times. Furthermore, the error line is interestingly Integer key = allKeys.next(); What could be the cause of this exception?
You cannot use the list's Iterator object at all when you are removing items while looping.
If you are removing all the items from the list:
while (!list.isEmpty()) {
Integer i = list.remove(0);
//Do something with the item
}
Otherwise, you can iterate without the iterator:
for (int i = 0; i < list.length(); i++) {
//Do something with the list
}
Related
This question already has answers here:
ArrayIndexOutOfBoundsException on a initialized Vector
(1 answer)
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Initial size for the ArrayList
(17 answers)
Closed 4 years ago.
I've read the documentation and looked at scores of SO questions and still can't create a vector of vectors without running into the ArrayIndexOutofBounds exception. For some context, I am creating a matrix, where each slot contains a reference to an edge, representing a flight from a source to a destination . Following one SO response, I set up my vector as follows.
Iterator<Edge> iter = array.iterator();
private Vector<Vector<Edge>> matrix = new Vector<Vector<Edge>>(9);
for (int i=0;i<9;i++){
matrix.add(i,new Vector<Edge>(9));
}
while (iter.hasNext()) {
Edge e = iter.next();
int s = e.source; //row
int d = e.destination; //col
Vector<Edge> row = matrix.get(s);
int size = row.size();
row.add(d, e); // Array Out of Bounds Exception
}
I believe I have initialized my inner and outer vectors and don't understand why the size of the vector is still zero. Do I have to initialize all the elements to null before I can start putting and getting elements? I would really appreciate your help.
new Vector<Edge>(9) creates an empty Vector of capacity 9. Therefore, calling add(d,e) for such a Vector when d is not 0 will throw ArrayIndexOutOfBoundsException.
To initialize each row Vector with null values, use:
for (int i = 0; i < 9; i++) {
Vector<Edge> v = new Vector<>(9);
matrix.add(v);
for (int j = 0; j < 9; j++)
v.add(null);
}
Constructs an empty vector with the specified initial capacity and with its capacity increment equal to zero.
Parameters:
initialCapacity the initial capacity of the vector
Throws:
java.lang.IllegalArgumentException if the specified initial capacity is negative
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
I have been coding a basic method to take an array of strings, find the largest length and return a string array containing on values that are equal to the highest length of the array. I keep getting a null pointer exception and i am not sure why. The code is:
String[] allLongestStrings(String[] inputArray) {
int compare = 0;
int k = 0;
String[] use = new String[20];
for (int i = 0; i < inputArray.length; i++) {
if (inputArray[i].length() > compare)
compare = inputArray[i].length();
}
for (int j = 0; j < 20; j++) {
if (inputArray[j].length() - compare == 0) {
use[k] = inputArray[j];
k++;
}
}
return use;
}
for (int j = 0; j < 20; j++) {
if (inputArray[j].length() - compare == 0) {
use[k] = inputArray[j];
k++;
}
}
This will only work if inputArray has at least 20 elements. In the code above, you're doing the correct thing: for (int i = 0; i < inputArray.length; i++). I think you just need to change this second for statement to be the lesser of 20 or the length of inputArray.
inputArray doesn't contain 20 elements. Don't just throw out and hard code a length value for your the array you're going to return. Actually determine what the true length is going to be because you could be too low on that value and if your not then you could end up with a bunch of null elements.
If allowed use an ArrayList or String List object which doesn't require a preset length (size) instead of a 1D String Array which does require length initialization: List<String> list = new ArrayList<>();. You can simply just add to it with the List.add() method.
If you must use a Single Dimensional Array then use another for loop to determine how many string elements actually have the same length as what is held within the compare integer variable. Always iterate through the original array (inputArray). This for loop would be very much like your second for loop except you would increment a integer counter variable upon all elemental lengths that equal the value held within the compare variable.
Eliminate the formula in your if statement condition contained within your second for loop. I think (IMHO): if (inputArray[i].length() == compare) {...} should be sufficient, it's much easier on the eyes. ;)
Just a thought for pizazz....perhaps add the actual Array index to the string that is added to the 1D String array named used. Use a delimiter of some sort to separate the two.
I am implementing logic within a for-loop that will remove any dog objects with status "ACCEPTED" from a kennel Object.
Note that a Kennel can have a List of many dogs.
Loop:
allDogsInKennel = kennel.getDogsList();
for (int i = 0; i < allDogsInKennel.size(); i++) {
//delete any dog object with a status of Accepted
if (allDogsInKennel.get(i).getStatus() == "ACCEPTED") {
kennel.removeDog(allDogsInKennel.get(i));
}
}
removeDog method
public void removeDog(Dog d) {
this.dogList.remove(d);
}
The problem I have is e.g. all 6 dogs in the list should be removed, but at present only 3 are being removed.
Example:
original size of list = 6 items
Item removed from index 0 = 5 items
Item removed from index 1 = 4 items
item removed from index 2 = 3 items
Now in the next iteration the loop tries to remove from index 3 due to i++ condition, but the array will only go to index 2 as it now has only 3 items at indexes:
0, 1, 2
How can I change my logic above to ensure that all items are removed from the array?
You can add i-- when you delete an object from a list;
for (int i = 0; i < allDogsInKennel.size(); i++) {
//delete any dog object with a status of Accepted
if (allDogsInKennel.get(i).getStatus().equals("ACCEPTED")) {
kennel.removeDog(allDogsInKennel.get(i));
i--
}
}
Let's assume you have an arraylist and have string obj1, obj2, obj3
ArrayList<String> lst = new ArrayList<String>();
lst.add("obj1");
lst.add("obj2");
lst.add("obj3");
for (int i = 0; i < lst.size(); i++) {
String str = lst.get(i);
lst.remove(str); //list size decrease,
//so when you remove an object with index 0, your new list has obj2(at index 0) and obj3(at index 1)
//when i is increased, it will escape obj2, it never check it or access it.
//i--; //open to give a try
}
for (int i = 0; i < lst.size(); i++) {
System.out.println(lst.get(i)); //will print obj2
}
Expected is removing all items in the list, so I have to add i--
after remove method
How to count duplicates in ArrayList and count only once.
Here is what I have so far:
/**
* Gets the number of duplicates in the list.
* Get the next word. It is at index i. Does it match any of the words with index > i?)
* #return the number of duplicate words in the list
*/
public int countDuplicates() {
int duplicates = 0;
for (int i = 0; i < list.size(); i++) {
for (int j = i; j < list.size(); j++) {
if (list.get(i).equals(j)) duplicates++;
}
}
return duplicates;
}
Here is check output:
Actual: 0
Expected: 3
I am missing something very easy. However, couldn't find what exactly it is.
How to solve this trouble?
You don't get the jth element you just compare to j directly. And as a commenter points out, j should start at i+1 to avoid comparing an element to itself. Therefore, you need to write
public int countDuplicates()
{
int duplicates = 0;
for (int i = 0; i < list.size(); i++) {
for (int j = i+1; j < list.size(); j++) {
if (list.get(i).equals(list.get(j))) duplicates++;
}
}
return duplicates;
}
Should be:
public int countDuplicates()
{
int duplicates = 0;
// TODO: Write the code to get the number of duplicates in the list
for (int i = 0; i < list.size(); i++) {
for (int j = i + 1; j < list.size(); j++) {
if (list.get(i).equals(list.get(j))) duplicates++;
}
}
return duplicates;
}
Use two sets for this:
final Set<X> set = new HashSet<>();
final Set<X> dups = new HashSet<>();
int dupCount = 0;
for (final X x: list) {
if (set.add(x)) // first time the element is seen
continue;
// Dup; see whether it is the first time we see it
if (dups.add(x))
dupCount++;
}
return dupCount;
This relies on the fact that Set's .add() returns true if and only if the set has been modified as the result of the operation. And note that it traverses the list only once.
I can see three problems with your current code:
You are not comparing pairs of elements. You are actually comparing an element with an index.
Your inner loop is comparing element i and element i ... and that would result in a false "duplicate" count.
If you have more than 2 copies of any given element, then you will get too many duplicate counts. (To see why, try to "hand execute" with a list of (say) three identical elements.
In fact, you have to EITHER use an auxiliary data structure (e.g. 2 Sets or a Map) OR modify the input list to avoid counting duplicates more than once.
I would note that your statement of the problem is ambiguous. "... only count each duplicate once" could mean that '[1, 1, 1]' gives either 1 or 2. It depends whether you consider each individual 1 to be a duplicate to be counted once or that we have 1 as one of a set of duplicates ... that must only be counted once.
You are comparing index j value instead of value of list list.get(j).
Do
if (list.get(i).equals(list.get(j)))
instead of
if (list.get(i).equals(j))
I have an arraylist populated by four elements, the order of which is random (they are put here by random from another arraylist). I then have a for loop that repeats 10 times, at the end of each repetition I use the clear methods to clear all the elements of the arraylist. However, when I start a new repetition, I would like to repopulate my arraylist with the old (previously worked with) elements that were members of the list in the previous repetition, so that I can use the elements again. And I would like to repeat that until I get out of my 10-repetition for loop. Is there any way to achieve this at all?
Code in addition to my question:
ArrayList<String> answerPegs = new ArrayList<String>();
// add element to ArrayList
ArrayList<String> mySecretAnswer = new ArrayList<String>();
for (int n = 4; n > 0; n--)
{
//populate mySecretAnswer with elements from answerPegs
}
ArrayList<String> clone1 = mySecretAnswer;
for (int q = 0; q < 10; q++) {
for (o = 0; o < 4; o++)
{
}
// called clear() method here
} // END OF 10-ROW LOOP
I would suggest simply having 2 lists - keep a pristine copy of the original list, and then iterate over + clear a copy of that list.
public void doRepetitions(List<Object> original)
{
for( int i=0; i<10; i++ )
{
List<Object> working = new ArrayList<Object>( original );
doStuffWithList(working);
}
}
Edit:
Since you've posted your code, I can give a more specific answer:
You can change your clone to be:
ArrayList<String> clone1 = new ArrayList<String>(mySecretAnswer);
And then move that to be inside your for loop:
for (int q = 0; q < 10; q++)
{
ArrayList<String> clone1 = new ArrayList<String>(mySecretAnswer);
// ....
}
Could you use 2 loops nested and just have the inner loop be the for loop 10 times then clear once at the end