I have an ArrayList of integers, I want to remove all the leading zeroes, code seems all right but U am getting unusual output.
Input:
0 0 0 1 9 9
Output:
0 1 9 9
Expected output:
1 9 9
public class Solution {
public ArrayList<Integer> plusOne(ArrayList<Integer> a) {
int flag=0;
//System.out.println(a.size()+" "+a.get(2));
for(int i=0;i<a.size();i++)
{
if(flag==0)
{
//System.out.println("val of i="+i+" "+a.get(i));
if(a.get(i)==0){
a.remove(i);
//System.out.println(flag);
}
else
{
//System.out.println("flag="+flag+" i="+i+" value"+a.get(i));
flag=1;
//System.out.println("flag="+flag+" i="+i+" value"+a.get(i));
}
}
if(flag==1)
break;
}
System.out.println();
return a;
}
}
You can remove the leading zeros by just searching for the first non-zero value, and then clearing the preceding sublist:
Iterator<Integer> it = list.iterator();
int i = 0;
while (it.hasNext() && it.next() == 0) {
++i;
}
list.subList(0, i).clear();
Removing a block of the list like this can be more efficient than removing the elements one at a time. e.g. if you removed them one at a time, ArrayList would shift all of the tail elements one position along each time, so the removal would be O(n^2).
The problem is that you're removing elements from the list while you're iterating over it. When i = 0:
a.remove(i);
removes the first element of the list and all elements are shifted: the 2nd becomes the 1st, etc. Then in the for loop, i is set to 1 after that. Hence, the second element is ignored: it became the first after the remove operation and i jumped over it because it was incremented.
The ugly solution would be to have i--; right after a.remove(i); to account for that shift.
However, a better solution would be to use a ListIterator:
public ArrayList<Integer> plusOne(ArrayList<Integer> a) {
ListIterator<Integer> it = a.listIterator();
while (it.hasNext() && it.next() == 0) {
it.remove();
}
return a;
}
This code retrieves it with listIterator(). While there are still elements and the next element is 0, we remove it with remove().
The problem is that i is incrementing while a.size() is shrinking. When i==0 you remove element 0 so all the values shift down 1, and next you remove element 1 but element 0 is also 0 so you skip this. i.e. you are only removing half the leading zeros.
BTW You should be able to confirm this by stepping through your code in your debugger. Helping you understand your code and find bugs is what it is for.
The simplest change is
for (int i = 0, max = a.size(); i < max; i++)
and
// you only want to check the first element.
if (a.get(0) == 0)
a.remove(0);
A more efficient way of doing this is to find the first element which is not 0 and return a sub list
public static List<Integer> trimLeadingZeros(List<Integer> list) {
for (int i = 0; i < list.size(); i++)
if (list.get(i) != 0)
return list.subList(i, list.size());
return Collections.emptyList();
}
Logic: anytime you see 0, loop from that point to the end, if inside that loop you see anything other than 0, break out from that loop.
Code:
//a is arrayList;
int count = 0;
for(int c = b; c < size; c++){
if(a.get(c) == 0 )
{
count++;
}
}
//size = 10,saw zero at 6th position that means leading zeros has to be 4,
// b is when I first saw 0
if(count == (size -b)) {}
else {
//else we just copy
ret.add(b, a.get(b));
}
Loop through the ArrayList and if you encounter 0 just remove it.
while (i < a.size() - 1 && a.get(i) == 0) {
a.remove(i);
}
Best Solution:
while(a.get(0)==0) { a.remove(0); }
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();
}
}
I am not sure why I am returning false for the first test run as shown in the test table attachment. This was one of my assignments last semester and I never figured out how to solve it:/ My assignment was to:
Write the definition of a method , oddsMatchEvens, whose two parameters are arrays of integers of equal size. The size of each array is an even number. The method returns true if and only if the even-indexed elements of the first array equal the odd-indexed elements of the second, in sequence. That is if w is the first array and q the second array , w[0] equals q[1], and w[2] equals q[3], and so on.
Test table
My code was:
public boolean oddsMatchEvens(int[] w, int[] q) {
int count = 0;
for (int i = 0; i < w.length; i++) {
if (w[i] == q[i + 1])
count++;
if (count == (w.length - 1))
return true;
}
return false;
}
if (count == (w.length - 1))
return true;
This is wrong, since you have only w.length/2 indices which you have to compare.
You should just return false, if w[i] != q[i+1].
And you should increase i by 2, not by 1.
There are two problems with the code:
Firstly, it is clearly mentioned the two input arrays are of equal length and you have to compare them even index to odd index. So the corner case occurs when you are checking last item of first array with last+1 item of second array(which doesn't exist as arrays are of equal length.
Secondly, you have to check first array even with second array odd so increment should be i+=2 and not i++.
Correct code with optimization(if one check fails you can come out of loop):
public boolean oddsMatchEvens(int[] w, int[] q) {
for (int i = 0; i < w.length-1; i+=2) {
if (w[i] != q[i + 1])
return false;
else
continue;
}
return true;
}
public boolean oddsMatchEvens (int []w, int []q) {
for (int j = 0; j < w.length-1; j+=2) {
if (w [j] != q [j+1])
return false;
continue;
}
return true;
}
So I'm currently stuck on one of my programs. I have to use a for loop to remove all elements in the ArrayList that's greater than 4. I have no idea how to do this. Someone help?
Here is my code:
import java.util.ArrayList;
public class P4E
{
public static void main( String args[] )
{
ArrayList<String> universities = new ArrayList<String>();
universities.add("Princeton");
universities.add("UCSD");
universities.add("UCLA");
universities.add("SDSU");
universities.add("UCI");
int size = universities.size();
System.out.println( "The size of the ArrayList is: " + size);
System.out.println("");
System.out.println("Now using a for-each loop");
System.out.println("");
for (String a : universities)
{
System.out.println( a );
}//end for-each
System.out.println( "" );
System.out.println( "Now using a for loop" );
System.out.println( "" );
for (int i = 0; i < universities.size(); i++)
{
if (universities.get(i) > 4 )
{
universities.remove(i);
}//end if-statement
}//end for loop
}//end main
}
Use the Java 8 removeIf default method on List:
universities.removeIf(u -> u.length() > 4);
If you're trying to remove elements that are larger than 4 characters, this will work:
for (int i = 0; i < universities.size(); i++)
{
System.out.println("checking "+universities.get(i));
if (universities.get(i).length() > 4 )
{
universities.remove(i);
i--;
}//end if-statement
}//end for loop
The .length() is necessary because you're interested in the size of the string, you can't compare a string to an int directly. The i--; ensures that you don't skip over elements as the size of the list changes.
The System.out.println is to show you what elements it is checking, so you can see that you're walking through the list correctly.
Instead of if(universities.get(i) > 4)
Do this:
for (int i = size; i >= 0; i--)
{
if (i > 4 )
universities.remove(i); // Shorten to only 1 line instead of brackets
}//end for loop
Reason
You want to remove the university at point i in this case, not get the university object. When you call universities.get(i) it returns the Object in the universities ArrayList
With current code problem is in the fact that you increasing i every time, while sometimes you remove element which cause indexes for elements to the left to be shifted. This results in the fact that you skip check for some elements. Example:
Initial array: [5,6,7], index i = 0.
You removed element at index 0 - array became [6,7], then you increase i and it became 1 - so index for next element to check is 1 and this reffer to 7, not to 6. Result - you didn't check 6.
Solutions:
1) Add i--; immediately after universities.remove(i);
2) Iterate in descending order: for (int i = 0; i < universities.size(); i++) -> for (int i = universities.size() - 1; i >= 0; i--)
3) Use java streams:
universities = universities.stream()
.filter(e -> e > 4)
.collect(Collectors.toList());
The problem with your code is that i advances to the next value even after a remove() call, meaning that your code will skip some items.
Here is what's happening: let's say you want to delete all numbers 4 and above from this list: {9 5 7 4 3}. When i is zero, your algorithm will find 9 and remove it. Now i is 1, but your list is {5 7 4 3}, so 5 at index zero will never be checked again.
One solution is to iterate in reverse order:
for (int i = universities.size() - 1; i >= 0 ; i--) {
if (universities.get(i).length() > 4 ) {
universities.remove(i);
}//end if-statement
}//end for loop
Now that i goes down instead of going up it does not matter whether the list shrinks or not.
What exactly do you mean by greater than 4? If you meant length of the String greater than 4, then here is the solution. Replace the 2nd for loop with the code below.
int i = 0;
while(i<universities.size()) {
if (universities.get(i).length() > 4 ) {
universities.remove(i);
} else {
i++;
}
}
I have a for loop looping through each element in an arrayList performing someMethod() on them, depending on the result of that method I either want to keep or remove that element from the list. for example:
int returnResult;
for (int i=0;i<4;i++){
returnResult = someMethod(arrayList.get(i));
if (returnResult == -1){
arrayList.remove(i);
}
}
My question is; if i have say 5 elements in the list and on the second iteration through the loop (so when i=1), I remove that element, when I go through the 3rd iteration will arrayList.get(2) be referencing what was actually the 4th element? i.e. does it immediately reduce the stack size?
Yes, it does. In order to get around this, you can iterate through the array in reverse.
int returnResult;
for (int i=3;i>=0;i--){
returnResult = someMethod(arrayList.get(i));
if (returnResult == -1){
arrayList.remove(i);
}
}
This pops them off from the end, and doesn't affect the elements left to go through.
Replace your code with this :
int returnResult, limit = 4;
for (int i=0; i < limit; i++){
returnResult = someMethod(arrayList.get(i));
if (returnResult == -1){
arrayList.remove(i);
limit--;
}
}
I am working on an issue where i have an input integer list such as {0,3,6,9,12,18,21,24,27,33,39}. I need to create a new list by analyzing the original list such that if i find a sequence of multiple of 3, then first element and last element of that sequence will both be added to that list. None of the elements between the first and last element of that sequence will be added. Any other elements (without consecutive multiples of 3) will be added as such. So for an input list of {0,3,6,9,12,18,24,27,30,39,45}, my output should be [0,12,18,24,30,39,45]. Note that my first sequence of multiples of 3s was 0,3,6,9,12; so based on my requirements, the new list has 0, 12. Since 18 does not have any neighbor that differs by 3 on either side, it is added as such. Similarly, 24,27,30 are added as 24,30. Also, similar to 18, 39 and 45 are added as such. Below is my code snippet:
int difference = 3;
public static List<Integer> parseList(List<Integer> input, int difference) {
List<Integer> output = new ArrayList<Integer> ();
for (int i = 0; i < input.size()-1; i++) {
// Check if subsequent element values differ by specific difference
if ( (input.get(i+1) - input.get(i)) == difference) {
output.add(input.get(i));
output.add(input.get(i+1));
}
else {
output.add(input.get(i));
}
}
return output;
}
My resulting output is: 0 3 3 6 6 9 9 12 12 18 24 27 27 30 30 39
Again, my expected output is: [0,12,18,24,30,39,45]
Note that not only i am getting intermediate duplicate values, i am also missing last value (i.e.45).
As mentioned in another post, you do not get the last element of the list because your for loop terminates on the next to last element of the input list. However, if you just adjust the end condition of your for loop, you will eventually get an IndexOutOfBoundsException because your algorithm checks for i+1 on each loop.
I think it is simpler to start at index 1 and simply look backward in the array instead. From your description of the problem, I understand that you will always use the first element of the list, so we can insert it right from the start (but that means you need to make sure the input list contains at least one element):
public static List<Integer> parseList(List<Integer> input, int difference) {
List<Integer> output = new ArrayList<Integer> ();
if (input.size() > 0) {
// always use first element
int indexToAdd = -1;
output.add(input.get(0));
for (int i = 1; i < input.size(); i++) {
if ( (input.get(i) - input.get(i-1)) == difference) {
if (i == input.size()-1) {
output.add(input.get(i));
}
else {
indexToAdd = i;
}
}
else {
if(indexToAdd != -1) {
output.add(input.get(indexToAdd));
indexToAdd = -1;
}
output.add(input.get(i));
}
}
}
return output;
}
for (int i = 0; i < input.size()-1; i++)
This causes you to miss the last element in the list.
Therefore you should add the last element after the loop (since the last element should always appear in the output).
The following:
if ( (input.get(i+1) - input.get(i)) == difference) {
output.add(input.get(i));
output.add(input.get(i+1));
causes the duplicate entries, since whenever you encounter a couple of elements that differ by 3, you enter both of them.
Instead, when you discover that the difference is three, you should set some flag to true, and set it to false otherwise. As long as the flag is true, you don't put elements in the output list.
I believe something like this will do the trick:
public static List<Integer> parseList(List<Integer> input, int difference) {
List<Integer> output = new ArrayList<Integer> ();
boolean isSeq = false;
for (int i = 0; i < input.size()-1; i++) {
if ((input.get(i+1) - input.get(i)) == difference) {
// add start of a sequence
if (!isSeq) {
output.add(input.get(i));
isSeq = true;
}
}
else {
isSeq = false;
output.add(input.get(i));
}
}
output.add(input.get(input.size()-1));
return output;
}
The method parseList in your code is incorrect. Two issues are in this method.
1.It will add the numbers as long as adjacent numbers differ by 3. In this situation you will add duplicate numbers when consecutive differ occurs.
For example, 0,3,6,9,12
Step#1. when i =0, condition 'adjacent numbers differ by 3 ' satisfiies, you add 0 and 3 to the output list.
step#2 when i =1, condition 'adjacent numbers differ by 3 ' satisfiies, yop add 3 and 6 to the output list, see what? duplicate values are added. for the index i=1, you add the number to output list both in step#1 and step#2. That is why you got duplicate numbers in your output list, such as 0,3,3,6....
2. Another issue in your parseList method is that the last number is not processed, it is ignored when the last 2 numbers not differs by 3. That is why you are not able to see it in your output list either.
You can add variable to check if consecutive number differ occurs and add logic to handle the last number as well.
The following code example can help you out with this problem.
It took me a while to figure it out.... Yet, another way to code it:
ArrayList<Integer> output = new ArrayList<Integer>();
int i = 0;
while (i < input.size()) {
int start = input.get(i);
output.add(start);
int end = -1;
int x = i+1;
while (x < input.size()) {
if (input.get(x++) - input.get(i++) != 3) {
end = input.get(i-1);
break;
}
}
if (end > 0 && end != start) {
output.add(end);
}
if (start == input.get(i)) break;
}
return output;