Related
This question already has answers here:
ArrayList.remove is not working in a loop
(7 answers)
Closed 2 years ago.
I'm trying to remove even-length words from a String ArrayList, and it's almost working, except that for some reason one even-numbered word is getting through.
My code:
public ArrayList<String> removeEvenLength(ArrayList<String> a) {
for (int i = 0; i < a.size(); i++) {
String wordEntry = a.get(i);
if (wordEntry.length() % 2 == 0) {
a.remove(i);
}
}
return a;
I must be missing something, but I'm failing to determine what exactly. Pointers much appreciated.
The issue is that you are modifying the ArrayList while iterating over it, which changes its size. You need to decrease the index by one each time you remove an element since that index will now refer to the next element.
public static ArrayList < String > removeEvenLength(ArrayList < String > a) {
for (int i = 0; i < a.size(); i++) {
String wordEntry = a.get(i);
if (wordEntry.length() % 2 == 0) {
a.remove(i);
i--;
}
}
return a;
}
Looping backwards will also fix this problem, as elements will never be shifted to a position that you have yet to check.
public static ArrayList < String > removeEvenLength(ArrayList < String > a) {
for (int i = a.size() - 1; i >= 0; i--) {
String wordEntry = a.get(i);
if (wordEntry.length() % 2 == 0) {
a.remove(i);
}
}
return a;
}
You can also use List#removeIf with Java 8 and up to accomplish this easier.
public static ArrayList < String > removeEvenLength(ArrayList < String > a) {
a.removeIf(str -> str.length() % 2 == 0);//or str.length() & 1 == 0
return a;
}
You can use Stream#filter to construct a new List with the odd-length Strings without modifying the old one.
public static ArrayList < String > removeEvenLength(ArrayList < String > a) {
return a.stream().filter(str -> str.length() % 2 == 1).collect(Collectors.toCollection(ArrayList::new));
}
Your code is working fine but as you will delete any element from a particular index then the list index will change means the immediate element after the removed element will be updated to removed element.
You can modify your code to below code:
public ArrayList<String> removeEvenLength(ArrayList<String> a) {
for (int i = 0; i < a.size(); i++) {
String wordEntry = a.get(i);
if (wordEntry.length() % 2 == 0) {
a.remove(i);
i-=1;
}
}
return a;
}
The issue here is that when you do a.remove(i);, the ArrayList automatically updates its indices, so you end up skipping a value. Here's an example of how this could happen:
You get the 1st element (a.get(0);)
You find that it is an even length string (wordEntry.length() % 2 == 0)
You remove it (a.remove(i);)
Your for loop advances to the next value (now i = 1)
You get what is now the 2nd element (a.get(1);), but because you removed what was the 1st element, this is now what used to be the 3rd element.
In this scenario, you skipped over that 2nd element, which is why some strings are slipping through unnoticed. This is where I would suggest using the enhanced for loop, which simplifies things significantly so you don't need to worry about what index you are on. It would look something like this:
public ArrayList<String> removeEvenLength(ArrayList<String> a) {
for (String wordEntry : a) {
if (wordEntry.length() % 2 == 0) {
a.remove(wordEntry);
}
}
return a;
}
Alternatively, if you want to go for an even simpler one-liner, ArrayList offers some very convenient methods for manipulating ArrayLists. One such method, called removeIf(), pretty much does exactly what you want, but I think it's good to learn to properly use for loops before going on to use built-in methods like this. That said, if you wanted to go that route, here's how I would do it:
public ArrayList<String> removeEvenLength(ArrayList<String> a) {
a.removeIf((wordEntry) -> wordEntry.length() % 2 == 0);
return a;
}
Also, I just felt that I should note that there are other ways of finding even numbers. You can also use (wordEntry.length() & 1) == 0. There's no real difference as far as performance or anything, it's really just personal preference, but I just felt I should mention another way of doing it :)
Your method gets out of sync with the elements when removing from front to back. So remove them in reverse order.
ArrayList<String> words = new ArrayList<>(List.of("abc", "efgh", "o", "pq", "rs"));
words = removeEvenLength(words);
System.out.println(words);
public static ArrayList<String> removeEvenLength(ArrayList<String> a) {
for (int i = a.size()-1; i >= 0; i--) {
String wordEntry = a.get(i);
if (wordEntry.length() % 2 == 0) {
a.remove(i);
}
}
return a;
}
And as stated you can also use removeIf()
Explanation.
As you move forward, removing elements, your index is still incrementing normally to get to the next element. But the list has changed by removing previous elements so the index may skip over elements that need to be checked.
Assume you want to remove even elements.
consider a = [5,20,40], index = 1
remove a[index++]; the list is now [5,40] and index = 2. 40 will not be checked because the list is now of size 2 and the iteration will cease.
By removing them in reverse, the decrease in the length of the list does not impact the index.
again consider a = [5,20,40], index = 2
remove a[index--]; the list is now [5,20] and index = 1. 20 will be checked and removed. Index will then be 0 and one element will remain.
This behavior can be mitigated by adjusting the index when removing items. However, by removing in reverse order, no such adjustment is required.
Remove while iterating makes the problem. You can use removeIf for this
a.removeIf(wordEntry -> (wordEntry.length() % 2 == 0));
or use ListIterator to iterate the arraylist
ListIterator<String> iter = a.listIterator();
while(iter.hasNext()){
if(iter.next().length() % 2 == 0){
iter.remove();
}
}
Beginner question : is there a way to split for loop in Java ?
for example the below, i would like to split
for(int i=0; i<bucket.size(); i++){
do something
}
Lets say bucket.size = 10
Split into two.
do something for the first 9 values in bucket
do something for the last value in bucket
Most directly:
for(int i=0; i<bucket.size()-1; ++i){
do something
}
do something else
Using List.sublist
for (Buck buck : bucket.subList(0, bucket.size()-1)) {
do something
}
// (Might want to check exists...)
Buck buck = bucket.get(bucket.size()-1);
do something else
If you are using a LinkedList, you can call removeLast method that removes and return the last element.
LinkedList<Integer> bucket= new LinkedList<>();
int last = bucket.removeLast();
// do something with the last item here
for (Integer i : bucket) {
// Do something for all items except the last one
}
for (int i=0; i<bucket.size()-1; i++){
if (i < 9)
{
//DO
}
else if (i == bucket.size()-2)
//-2 because the loop condition is < not <= but also includes a -1
//Only works with bucket size 11 or greater or it will just enter the i< 9 instead
{
//DO for final time in loop
}
}
Just use some if else conditions inside the block to find what you need.
You can use && for AND, || for OR, and then of course < > <= >= ==
Your loop will only execute 9 times though since you have it < AND -1, so the question is a little bit weird. The final time IS the 9th time, so you only really need to the i < 9, in the case of 10. The loop should really be:
int size = 10;
for (int i=0; i<=size-1; i++){
}
If you want the loop to execute 10 times.
I'd use a while loop
int i = 0;
while(i < (bucket.size() - 1))
{
//do first nine
i++;
}
//do last one
If you want do only do something for the last value then just do it. This presumes a non-empty list as stated by the OP.
// Doing something for first size-1 values.
for(int i=0; i<bucket.size()-1; i++){
// do something with
bucket.get(i);
}
// Now do something with last value.
bucket.get(bucket.size()-1);
you can take advantage of skip and limit methods from Stream
//first 9 elements
bucket.stream().limit(9).forEach(s -> {
//do smth
});
//remaining elements
bucket.stream().skip(9).forEach(s -> {
//do smth
});
Well, there's lots of ways for you to achieve this. If your intend is just to do something else to the last element and something to the others I think you should do something like this:
int lastIndex = bucket.size() - 1;
for (int i = 0; i < lastIndex; i++) {
Type item = bucket.get(i);
//do something with item
}
if(lastIndex != -1) {
Type item = bucket.get(lastIndex);
// do something else with item
}
This way, you avoid comparing every time and save one iteration (Not a big advantage, I know).
Although, if your list is really large and you need an efficient way, or even your use case is more complicated, you should consider using Spliterators:
https://www.baeldung.com/java-spliterator
This question already has answers here:
Understanding this removeAll java method with arrayList
(3 answers)
Closed 6 years ago.
This methods duty is to remove all occurrences of the value toRemove from the arrayList. The remaining elements should just be shifted toward the beginning of the list. (the size will not change.) All "extra" elements at the end (however many occurrences of toRemove were in the list) should just be filled with 0. The method has no return value, and if the list has no elements, it should just have no effect.
Cannot use remove() and removeAll() from the ArrayList class.
The method signature is:
public static void removeAll(ArrayList<Integer> list, int toRemove);
The solution:
public static void removeAll(ArrayList<Integer> list, int toRemove) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i) = toRemove) {
for (int j = i + 1; j < list.size(); j++) {
list.set(j - 1, list.get(j));
}
list.set(list.size() - 1, 0);
i--;
}
}
I understand the first for loop and the if statement well. Because one would want to iterate through the entire arrayList one-by-one and for each index with a number present in the arrayList check if it is, in fact the toRemovee integer. After this point I become lost.
Why another for loop?
Why are we taking the previous loops variable and adding 1 to it?
why within this second loop are we using the parameters "list" and using a set method?
why j - 1?
why list.get(j)?
Why after this second loop is over is there the line:
list.set(list. sise () - 1, 0) ?
why the i--?
There are a lot of moving parts and I would like to understand the logic.
Thank you
Firstly the if statement is assignment operation which isn't correct. You need to change the = to ==. I have explained each step in the code -
public static void removeAll(ArrayList<Integer> list, int toRemove) {
//start with the first number in the list until the end searching for toRemove's
for (int i = 0; i < list.size(); i++) {
//if the value at i is the one we want to remove then we want to shift
if (list.get(i) == toRemove) {
//start at the index to the right until the end
//for every element we want to shift it the element to its left (i == j - 1)
for (int j = i + 1; j < list.size(); j++) {
//change every value to whatever was to the right of it
//this will overwrite all values starting at the index where we found toRemove
list.set(j - 1, list.get(j));
}
//now that everything is shifted to the left, set the last element to a 0
list.set(list.size() - 1, 0);
//decrement to adjust for the newly shifted elements
// this accounts for the case where we have two toRemoves in a row
i--;
}
}
}
By the end of this function any value that matches toRemove is "removed" by shifting the arraylist to the left everytime the value is found and the last element will be set to 0.
Example
removeAll([1,2,3,4,5,5,6,7,8,5,9,5], 5)
Output
[1,2,3,4,6,7,8,5,9,0,0,0]
Please see the following to learn details (from minute 5:50 or 5:57)
https://www.youtube.com/watch?v=qTdRJLmnhQM
You need the second for loop ,to take all elements after the element you’ve removed it and shift it over one to the left so basically it’s filling up the space that is left empty from removing it so this is what this is doing.
So the original code is
// An (unsorted) integer list class with a method to add an
// integer to the list and a toString method that returns the contents
// of the list with indices.
//
// ****************************************************************
public class IntList {
private int[] list;
private int numElements = 0;
//-------------------------------------------------------------
// Constructor -- creates an integer list of a given size.
//-------------------------------------------------------------
public IntList(int size) {
list = new int[size];
}
//------------------------------------------------------------
// Adds an integer to the list. If the list is full,
// prints a message and does nothing.
//------------------------------------------------------------
public void add(int value) {
if (numElements == list.length) {
System.out.println("Can't add, list is full");
} else {
list[numElements] = value;
numElements++;
}
}
//-------------------------------------------------------------
// Returns a string containing the elements of the list with their
// indices.
//-------------------------------------------------------------
public String toString() {
String returnString = "";
for (int i = 0; i < numElements; i++) {
returnString += i + ": " + list[i] + "\n";
}
return returnString;
}
}
and
// ***************************************************************
// ListTest.java
//
// A simple test program that creates an IntList, puts some
// ints in it, and prints the list.
//
// ***************************************************************
import java.util.Scanner ;
public class ListTest {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
IntList myList = new IntList(10);
int count = 0;
int num;
while (count < 10) {
System.out.println("Please enter a number, enter 0 to quit:");
num = scan.nextInt();
if (num != 0) {
myList.add(num);
count++;
} else {
break;
}
}
System.out.println(myList);
}
}
I need to change the add method to sort from lowest to highest. This is what I tried doing.
// An (unsorted) integer list class with a method to add an
// integer to the list and a toString method that returns the contents
// of the list with indices.
//
// ****************************************************************
public class IntList {
private int[] list;
private int numElements = 0;
//-------------------------------------------------------------
// Constructor -- creates an integer list of a given size.
//-------------------------------------------------------------
public IntList(int size) {
list = new int[size];
}
//------------------------------------------------------------
// Adds an integer to the list. If the list is full,
// prints a message and does nothing.
//------------------------------------------------------------
public void add(int value) {
if (numElements == list.length) {
System.out.println("Can't add, list is full");
} else {
list[numElements] = value;
numElements++;
for (int i = 0; i < list.length; i++) {
if (list[i] > value) {
for (int j = list.length - 1; j > i; j--) {
list[j] = list[j - 1];
list[i] = value;
break;
}
}
}
for (in i = 0; i < list.length; i++) {
}
}
}
//-------------------------------------------------------------
// Returns a string containing the elements of the list with their
// indices.
//-------------------------------------------------------------
public String toString() {
String returnString = "";
for (int i = 0; i < numElements; i++) {
returnString += i + ": " + list[i] + "\n";
}
return returnString;
}
}
The outcome is very wrong. Any one able to steer me in the right direction? I can sort of see why what I have doesn't work, but I can't see enough to fix it.
So I realize I was not very descriptive here the first time. With the exception of the add method modifications the code was not my doing. My assignment is to only touch the add method to sort the array to print out smallest to largest. This is a beginners class and we do little to no practice my only tools for this are some basic understandings of loops and arrays.
I tried redoing it again and came up with this:
if(list[numElements-1] > value){
for(int i=0; i<numElements; i++){
if(list[i]>value){
for(int j = numElements; j>i; j-- ){
list[j] = list[j-1];
}
list[i] = value;
break;
}
}
numElements++;
}
else
{
list[numElements] = value;
numElements++;
}
my input was:8,6,5,4,3,7,1,2,9,10
the output was: 1,10,1,9,10,1,1,2,9,10
this thing is kicking my butt. I understand I want to check the input number to the array and move all numbers higher than it up one space and enter it behind those so it is sorted on entry, but doing so is proving difficult for me. I apologize if my code on here is hard to follow formatting is a little odd on here for me and time only allows for me to do my best. I think break is not breaking the for loop with i like i thought it would. Maybe that is the problem.
The biggest bug I see is using list.length in your for loop,
for(int i = 0; i <list.length; i++)
you have numElements. Also, I think it's i that needs to stop one before like,
for(int i = 0; i < numElements - 1; i++)
and then
for (int j = numElements; j > i; j--)
There are two lines that have to be moved out of the inner loop:
for (int i = 0; i < list.length; i++) {
if (list[i] > value) {
for (int j = list.length - 1; j > i; j--) {
list[j] = list[j - 1];
// list[i] = value;
// break;
}
list[i] = value;
break:
}
}
In particular, the inner break means that the loop that is supposed to move all larger elements away to make room for the new value only runs once.
You might want to include Java.util.Arrays which has its own sort function:
http://www.tutorialspoint.com/java/util/arrays_sort_int.htm
Then you can do:
public void add(int value) {
if (numElements == list.length) {
System.out.println("Can't add, list is full");
}
else {
list[numElements] = value;
numElements++;
Arrays.sort(list);
//Or: Java.util.Arrays.sort(list);
}
}
As Eliott remarked, you are getting confused between list.length (the capacity of your list) and numElements (the current size of your list). Also, though, you do not need to completely sort the list on each addition if you simply make sure to insert each new element into the correct position in the first place. You can rely on the rest of the list already to be sorted. Here's a simple and fast way to do that:
public void add(int value) {
if (numElements == list.length) {
System.out.println("Can't add, list is full");
} else {
int insertionPoint = Arrays.binarySearch(list, 0, numElements);
if (insertionPoint < 0) {
insertionPoint = -(insertionPoint + 1);
}
System.arrayCopy(list, insertionPoint, list, insertionPoint + 1,
numElements - insertionPoint);
list[insertionPoint] = value;
numElements += 1;
}
}
That will perform better (though you may not care for this assignment), and it is much easier to see what's going on, at least for me.
Here are some hints.
First, numElements indicates how many elements are currently in the list. It's best if you change it only after you have finished adding your item, like the original method did. Otherwise it may confuse you into thinking you have more elements than you really do at the moment.
There is really no need for a nested loop to do proper adding. The logic you should be following is this:
I know everything already in the list is sorted.
If my number is bigger then the biggest number (which is the one indexed by numElements-1, because the list is sorted) then I can just add my number to the next available cell in the array (indexed by numElements) and then update numElements and I'm done.
If not, I need to start from the last element in the array (careful, don't look at the length of the array. The last element is indexed by numElements-1!), going down, and move each number one cell to the right. When I hit a cell that's lower than my number, I stop.
Moving all the high numbers one cell to the right caused one cell to become "empty". This is where I'm going to put my number. Update numElements, and done.
Suppose you want to add the number 7 to this array:
┌─┬──┬──┬─┬─┐
│3│14│92│-│-│
└─┴──┴──┴─┴─┘
⬆︎ Last element
You move everything starting from the last element (92) to the right. You stop at the 3 because it's not bigger than 7.
┌─┬─┬──┬──┬─┐
│3│-│14│92│-│
└─┴─┴──┴──┴─┘
(The second element will probably still contain 14, but you're going to change that in the next step so it doesn't matter. I just put a - there to indicate it's now free for you to enter your number)
┌─┬─┬──┬──┬─┐
│3│7│14│92│-│
└─┴─┴──┴──┴─┘
⬆︎ Updated last element
This requires just one loop, without nesting. Be careful and remember that the array starts from 0, so you have to make sure not to get an ArrayIndexOutOfBoundsException if your number happens to be lower than the lowest one.
One problem I spotted is that: you are trying to insert the newly added number into the array. However your loop:
for (int i = 0; i < list.length; i++) {
if (list[i] > value) {
for (int j = list.length - 1; j > i; j--) {
list[j] = list[j - 1];
list[i] = value;
break;
}
}
}
is always looped through the total length of the array, which is always 10 in your test, rather than the actual length of the array, i.e. how many numbers are actually in the array.
For example, when you add the first element, it still loops through all 10 elements of the array, although the last 9 slots does not have value and are automatically assigned zero.
This caused your if statement always returns true:
if (list[i] > value)
if you have to write the sort algorithm yourself, use one of the commonly used sorting algorithm, which can be found in Wikipedia.
If any one was curious I finally worked it out. Thank you to everyone who replied. This is what i ended up with.
public void add(int value)
{
if(numElements == 0){
list[numElements] = value;
numElements++;
}
else{
list[numElements] = value;
for(int check = 0; check < numElements; check++){
if(list[check] > value){
for(int swap = numElements; swap> check; swap--){
list[swap] = list[swap-1];
}
list[check] = value;
break;
}
}
numElements++;
}
}
so my original is the same but we have to make another class
A Sorted Integer List
File IntList.java contains code for an integer list class. Save it to your project and study it; notice that the only things you can do are create a list of a fixed size and add an element to a list. If the list is already full, a message will be printed. File ListTest.java contains code for a class that creates an IntList, puts some values in it, and prints it. Save this to your folder and compile and run it to see how it works.
Now write a class SortedIntList that extends IntList. SortedIntList should be just like IntList except that its elements should always be in sorted order from smallest to largest. This means that when an element is inserted into a SortedIntList it should be put into its sorted place, not just at the end of the array. To do this you’ll need to do two things when you add a new element:
Walk down the array until you find the place where the new element should go. Since the list is already sorted you can just keep looking at elements until you find one that is at least as big as the one to be inserted.
Move down every element that will go after the new element, that is, everything from the one you stop on to the end. This creates a slot in which you can put the new element. Be careful about the order in which you move them or you’ll overwrite your data!
Now you can insert the new element in the location you originally stopped on.
All of this will go into your add method, which will override the add method for the IntList class. (Be sure to also check to see if you need to expand the array, just as in the IntList add() method.) What other methods, if any, do you need to override?
To test your class, modify ListTest.java so that after it creates and prints the IntList, it creates and prints a SortedIntList containing the same elements (inserted in the same order). When the list is printed, they should come out in sorted order.
so I'm working on my Java assignment where I'm given a big array.
I'm told to print the first 20 items in the array in reverse order,
then print the next 20 items in reverse order again, and so forth until I reach the end of the array.
I was able to work out how to print the first items in reverse, but then I'm having trouble implementing something that would let me continue where I left from the original array.
I'm also only allowed to have 21 items stored at a time.
Here's what I have so far (50items instead of 20)
public static void doIt(BufferedReader r, PrintWriter w) throws IOException {
LinkedList<String> s = new LinkedList<String>();
int counter = 0;
int max = 50;
for (String line = r.readLine(); line != null; line = r.readLine()) {
if (counter < max) {
s.addFirst(line);
counter++;
}
if (counter == max) {
for (String n : s) {
System.out.println(n);
}
}
}
}
I was wondering if someone can help me out, not sure what I can do from here.
First, you need to print the list whenever counter hits a multiple of 20 as well as when it hits max. Then, after you print the contents of s, clear the list:
s.clear();
That will remove all elements so it will fill up again. You also need to print the list after the for loop exits, otherwise the last few items will be left unprinted.
Note that you are not using an array anywhere in this code. It's not clear that you are following the spirit of the assignment by using a LinkedList. But only you know what the rubric is.
I hope this can get you started:
void example() {
for (int i = 0; i < 50; i++) { //fill array to be read (for this example)
myArray[i] = i;
}
readback();
}
void readback() {
int batch = 1; //represents a portion of the read operation
int batchSize = 20; //the size of the read portion
int pos = 0; //the current index of the array while it is being read
int hi; //the top of the batch
int lo; //the bottom of the batch
while (pos < myArray.length) {
if (batch*batchSize<myArray.length) { //make sure you are not going over the array boundary
hi = batch*batchSize;
lo = hi - batchSize;
} else {
hi = myArray.length;
lo = pos;
}
for (int i = hi - 1; i >= lo; i--) { //read
System.out.println(myArray[i]);
pos++;
}
batch++; //go to the next batch
}
}
For this part of the question:
I'm told to print the first 20 items in the array in reverse order, then print the next 20 items in reverse order again, and so forth until I reach the end of the array.
One simple solution would be to:
iterate 20 places in the array
store this position in a temp index
iterate back 20 places printing the array
repeat process from stored temp index
Also, keep in mind if the last print might have less than 20 elements.
int size = 20; // size of reversed chunks
for(int i = 0; i < array.length; i += size) {
int j = (i + (size - 1) < array.length) ? (i + size - 1) : array.length - 1;
for(; j >= i; j--) {
System.out.print(array[j] + " ");
}
}
However, there is no array in your code so I am not sure what you meant by that. You are reading values from a file and then using a LinkedList to print them in reverse. A better, more natural data structure, for printing in reverse (as well as most "reversal" operations) would be a Stack although Java's implementation for LinkedList is implemented such that it allows for Stack (LIFO) behavior. It is just generally used as a Queue (FIFO) structure. My answer will use a LinkedList as well to make it consistent with your approach but think about a Stack in this situation in the future.
So, since you are reading numbers, line by line from a file, here is what you can do:
You can read and insert the numbers at the top of a LinkedList until you reach the max value or the end of file
You already have that part working
Print all the numbers by removing them from the top of the LinkedList which will make them in reverse order
You are printing them but not removing them or clearing the list by calling s.clear()
Once you reach the end of file you could end up with values still in the LinkedList because you reached end of file before you reached max items and the loop finished but nothing was printed. Print these values as well.
Another thing, it seems like you are not writing to the file so you don't need the PrintWriter parameter of the function.
Here is the code:
public static void doIt(BufferedReader r) throws IOException {
LinkedList<String> s = new LinkedList<String>();
int counter = 0;
int max = 50;
for (String line = r.readLine(); line != null; line = r.readLine()) {
if (counter < max) {
s.addFirst(line);
counter++;
}
if (counter == max) {
while(!s.isEmpty()) { // remove and print in reverse order
System.out.println(s.removeFirst());
}
counter = 0; // reset counter
}
}
// print the remaining elements, if they exist
while(!s.isEmpty()) { // remove and print in reverse order
System.out.println(s.removeFirst());
}
}