I have a small problem, I want to go through a list and compare two objects of the array. Each object has 3 elements, I use a StringTokenizer to be able to remove the separator, so each object has 3 elements. I would like to know how to make a method that gets the third element of each object and compare them. And if that element is less than another delete that element and the 2 before it.
I tried to make them with an iterator but I wouldn't know very well that it started from the 3 element and increased the position by 3.
Iterator<Integer> it = lisM.iterator();
int num;
while (it.hasNext()){
num = it.next();
System.out.println(num);
}
Is --> if, I was wrong to put it in the picture
This only answers part of your question. I could not understand the question completely, please edit it and I can edit my answer.
You should not remove items from a list whilst in a for loop, therefore you can, for example, create another boolean list with the same size divided by 3 and just fill it with true Booleans then set the position divided by 3 to false if you want to delete the three items. Then you can create a new list, iterate over the boolean list and add 3 "Objects" which are actually Strings (thanks #JB Nizet) at a time, every time the boolean list element is true. When it is false you just don't add the elements and by doing so you are practically deleting the two elements before that element together with that element.
You casted a String to an int, that does not work you have to parse the Strings.
I corrected some of your code and added the boolean list here:
ArrayList<String> lisM = new ArrayList<>(); // here I initialise the list as an array list with strings.
ArrayList<Boolean> booleanList = new ArrayList<>();
for (int i = 0; i < lisM.size() / 3; i++) {
booleanList.add(true);
}
for(int i = 3; i < lisM.size();i+=3) {
int m = Integer.parseInt(lisM.get(i)); // here I changed the casting to parsing and moved it out of the for loop, there is no need to initialize it again every single time since you do not change it in the second for loop.
for (int j = 6; j < lisM.size(); j += 6) {
int m1 = Integer.parseInt(lisM.get(j));// here I changed the casting to parsing again.
if (m > m1) { // this makes no sense here because you are going over all of the elements of the list and comparing them to all of them. But I kept it here for the sake of example.
booleanList.set(i/3,false);
}
// if you want to go over the whole list you will have to clear the list and start over again for every element.
}
}
and here is how you could create the new list without the elements you do not want:
ArrayList<String> newLisM = new ArrayList<>();
for (int i = 0; i <booleanList.size(); i++) {
if(booleanList.get(i))
for (int j = 0; j < 3; j++) {
newLisM.add(lisM.get(i+j));
}
}
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);
I've done some research before posting this, but I still haven't quite grasped it yet. Basically I have 4 items in my Arraylist:
Bananas, Oranges, Apples and Pineapples
ArrayList<String> fruitList = new ArrayList<>();
addItems(){
fruitList.add("Banana");
fruitList.add("Oranges");
fruitList.add("Apples");
fruitList.add("Pineapples");
}
and I am trying to remain only with one. This is what I've tried so far:
for (int i = 0; i <= fruitList.size() - 1; i++) {
fruitList.remove(i);
}
from my understanding the code above should remove 3 items, however I get 2 items; (Oranges and Pineapples).
Kindly help me understand this in achieving the desired result.
The problem here is that the index goes up from the beginning of the list, while the size of the list is shrinking:
for (int i = 0; i <= fruitList.size() - 1; i++) {
fruitList.remove(i);
}
Not only it's confusing which elements get removed,
it's also very inefficient to remove elements from the middle of a list like this.
It would be better to use an index going from the end, as the other answer suggests.
A compact way to achieve the same is to use a sub-list and clear it:
fruitList.subList(1, fruitList.size()).clear();
System.out.println(fruitList);
// prints [Banana]
To remove all the items but the 1st:
for (int i = fruitList.size() - 1; i > 0 ; i--) {
fruitList.remove(i);
}
iterate backwards so the index is in sync with the changing size of the list.
If you do this:
int size = fruitList.size();
for (int i = 0; i < size - 1; i++) {
fruitList.remove(0);
}
you will remove all but the last, because at each iteration you remove the 1st item until there is only 1, which will not be removed.
for(int i = 0; i < bag.length; i++)
{
if(bag[i].equals(a))
{
tmp = bag[i];
bag[i] = bag[bag.length-1];
bag[bag.length-1] = tmp;
numElements--;
break;
}
}
The goal of this is to find an object in the array and then remove it? is it possible??
Changing the length of an array is not possible. Recall that array is a static data structure whose size is determined before hand. Increasing or decreasing is not supported in this data structure. The fact that one has to increase or decrease the size depending on the usecase means that they have picked up the wrong data structure. They should perhaps go with an ArrayList.
Anyway, coming back to your question, you can simulate the 'size decrease' by maintaining a variable which you let track the array index and decrease the size of this variable. This lets you give the impression of shrinking the array.
The code you have provided does the same. Note however, that you should be using this modified index to track the contents of your array.
for(int i = 0; i < bag.length; i++)
{
if(bag[i].equals(a))
{
tmp = bag[i];
bag[i] = bag[bag.length-1];
bag[bag.length-1] = tmp;
numElements--;
break;
}
}
Whenever a particular bag at a given index equals to the item under question i.e., 'a', we swap elements so that the current bag element to be removed moves to the last and also we reduce the size of our new index - numElements by 1 to simulate this.
If you have the full code with you, please consider adding the following snippet at the end of that program to understand this more:
// Simulation of the array shrinking.
for(int i = 0; i < numElements; i++)
{
System.out.println( bag[i] );
}
// Movement of uninteresting elements to the end of the array.
for(int i = 0; i < bag.length; i++)
{
System.out.println( bag[i] );
}
It's not possible to change the length of an array. You can overwrite the element you wish to remove with the last element of the array and then copy the first bag.length - 1 elements of your array to a new array whose length is bag.length - 1.
for(int i = 0; i < bag.length; i++) {
if(bag[i].equals(a)) {
bag[i] = bag[bag.length-1];
bag = Arrays.copyOf (bag, bag.length - 1);
break;
}
}
public static String[] removeElements(String[] input) {
List<String> result = new ArrayList<String>();
String deleteValue = "somevalue";
for(String item : input)
if(!deleteValue .equals(item))
result.add(item);
return result.toArray(input);
}
This is one method you can fit this into your program.
You cannot decrease the size of an array. okay no problem! you can create your own data structure which supports that right?
Now, create a class named say MyArray with functions like increaseLenght(int) and decreseLength(int). Try it if you want to, will be fun for sure..
You cannot reduce the size of an array. Arrays are fixed length. What you can do is have a variable that indicates how many entries of the array you are using. This is what you are doing with numElements. The standard class ArrayList is implemented like this. The data is kept in an array and a private field size is used. With an ArrayList, when you remove an element, all the elements to the right are shifted left. However I also like your idea.
I would suggest 2 changes.
Make the last element null instead. If you are removing the element, why does it still need to be in the array?
Use numElements - 1 rather than bag.length-1 as the array could be bigger.
With these changes it becomes:
for(int i = 0; i < bag.length; i++)
{
if(bag[i].equals(a))
{
bag[i] = bag[numElements-1];
bag[numElements-1] = null;
numElements--;
break;
}
}
In java programming:
I have something along the lines of
ArrayList<String> list = new ArrayList<String>();
int listSize = list.size();
for(int x = 0; x< listSize; x++){
list.remove(x);
listSize = list.size();
}
will this work well enough? or will the for loop keep running. Thanks!
I'm a bit concerned at what you're attempting to do here. Any time someone wants to remove items from a collection in a loop without using an Iterator, alarms usually go off.
So, to answer the question as stated: If you change your loop invariant, then you'll get some funky behavior. This is why it's often called an "invariant"; you don't want to change it. You're certainly welcome to, but you're playing with fire here.
But, let's assume that we have a list of 5 elements in it and we execute your code as is.
List<String> stringList = Arrays.asList("word", "another word", "let's go", "keep it up", "get moving");
int length = stringList.size();
for(int i = 0; i < length; i++) {
System.out.println(stringList.remove(i));
length = stringList.size();
}
System.out.println("done");
If you're expecting it to print out every word in the list, then think again. It will skip every element because we are changing the content of the list while iterating over it. When deleting elements from an ArrayList, the underlying implementation will shift over elements to the left in where it was deleted. So, if you delete from position 0, every element now lives to the left of its original position (so element 1 is now element 0).
A quick run-through:
First iteration, i = 0; "word" is removed. Size is changed to 4, i increases to 1.
Second iteration, i = 1; "let's go" is removed. Size is changed to 3, i increases to 2.
Third iteration, i = 2; "get moving" is removed. SIze is changed to 2, i increases to 3.
No further iteration happens as the condition is not satisfiable.
If you want to cleanly remove all items from the collection without printing them out, then ArrayList#clear() is what you're looking for. If you want to remove elements one at a time, then use an Iterator instead:
List<String> stringList = new ArrayList<>(Arrays.asList("word", "another word", "let's go", "keep it up", "get moving"));
for(Iterator<String> stringIterator = stringList.iterator(); stringIterator.hasNext(); ) {
System.out.println(stringIterator.next());
stringIterator.remove();
}
System.out.println("done");
The loop won't keep running and it will end without any exception. But the result may not what you expect.
Besides "ArrayList#clear()" or Iterator way to remove all elements from one array. You can also try below codes, just remove "x++" from your loop condition.
ArrayList<String> list = new ArrayList<String>();
int listSize = list.size();
for(int x = 0; x< listSize;){
list.remove(x);
listSize = list.size();
}
Why not do it in a "while" loop?
ArrayList<String> list = new ArrayList<String>();
int listSize = list.size();
while(list.size() != 0){
list.remove(x);
}
Technically, the computer science course would likely tell you to do it something like this:
public void solve() {
ArrayList<String> list = new ArrayList<String>();
Iterator iter = list.iterator();
while(iter.hasNext()) {
System.out.println("Next value is: " + iter.next());
iter.remove();
}
}
I'm trying to write a simple game where an enemy chases the player on a grid. I'm using the simple algorithm for pathfinding from the Wikipedia page on pathfinding. This involves creating two lists with each list item containing 3 integers. Here's test code I'm trying out to build and display such a list.
When I run the following code, it prints out the same numbers for each array in the ArrayList. Why does it do this?
public class ListTest {
public static void main(String[] args) {
ArrayList<Integer[]> list = new ArrayList<Integer[]>();
Integer[] point = new Integer[3];
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 3; j++) {
point[j] = (int)(Math.random() * 10);
}
//Doesn't this line add filled Integer[] point to the
//end of ArrayList list?
list.add(point);
//Added this line to confirm that Integer[] point is actually
//being filled with 3 random ints.
System.out.println(point[0] + "," + point[1] + "," + point[2]);
}
System.out.println();
//My current understanding is that this section should step through
//ArrayList list and retrieve each Integer[] point added above. It runs, but only
//the values of the last Integer[] point from above are displayed 10 times.
Iterator it = list.iterator();
while (it.hasNext()) {
point = (Integer[])it.next();
for (int i = 0; i < 3; i++) {
System.out.print(point[i] + ",");
}
System.out.println();
}
}
}
First of all, several of the other answers are misleading and/or incorrect. Note that an array is an object. So you can use them as elements in a list, no matter whether the arrays themselves contain primitive types or object references.
Next, declaring a variable as List<int[]> list is preferred over declaring it as ArrayList<int[]>. This allows you to easily change the List to a LinkedList or some other implementation without breaking the rest of your code because it is guaranteed to use only methods available in the List interface. For more information, you should research "programming to the interface."
Now to answer your real question, which was only added as a comment. Let's look at a few lines of your code:
Integer[] point = new Integer[3];
This line creates an array of Integers, obviously.
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 3; j++) {
point[j] = (int)(Math.random() * 10);
}
//Doesn't this line add filled Integer[] point to the
//end of ArrayList list?
list.add(point);
//...
}
Here you assign values to the elements of the array and then add a reference to the array to your List. Each time the loop iterates, you assign new values to the same array and add another reference to the same array to the List. This means that the List has 10 references to the same array which has been repeatedly written over.
Iterator it = list.iterator();
while (it.hasNext()) {
point = (Integer[])it.next();
for (int i = 0; i < 3; i++) {
System.out.print(point[i] + ",");
}
System.out.println();
}
}
Now this loop prints out the same array 10 times. The values in the array are the last ones set at the end of the previous loop.
To fix the problem, you simply need to be sure to create 10 different arrays.
One last issue: If you declare it as Iterator<Integer[]> it (or Iterator<int[]> it), you do not need to cast the return value of it.next(). In fact this is preferred because it is type-safe.
Finally, I want to ask what the ints in each array represent? You might want to revisit your program design and create a class that holds these three ints, either as an array or as three member variables.
I would highly recommend to enclose the integer array of 3 numbers into a meaningful class, that would hold, display and control an array of 3 integers.
Then in your main, you can have an growing ArrayList of objects of that class.
You have an extra ) here:
element = (int[])it.next()); //with the extra parenthesis the code will not compile
should be:
element = (int[])it.next();
Besides the problem in the other answer, you cal it.next() two times, that cause the iterator move forward two times, obviously that's not what you want. The code like this:
element = (int[])it.next());
String el = (String)element;
But actually, I don't see you used el. Although it's legal, it seems meaningless.