Reputation: 41
I am trying to clone items that have a char l in the string and remove items that have char r in the string, and do nothing when chars r and l exist in the same string, however, nothing seems to be happening when I implement the if statement I created for the clone, but works for everything else.
I created a for loop that will loop through each string in the arraylist list. It will first check if in that index there is both r and l in the string, and if there is it will continue, then it will check if there's an r in the string it'll delete it then return the list of strings, if not check if l and then add the same element in the last index of the list.
package com.codegym.task.task07.task0716;
import java.util.ArrayList;
/*
R or L
*/
public class Solution {
public static void main(String[] args) throws Exception {
ArrayList<String> list = new ArrayList<>();
list.add("rose"); // 0
list.add("love"); // 1
list.add("lyre"); // 2
list = fix(list);
for (String s : list) {
System.out.println(s);
}
}
public static ArrayList<String> fix(ArrayList<String> list) {
for (int i = 0; i < list.size(); i++)
{
if (list.get(i).contains("r") && list.get(i).contains("l"))
{
continue;
} else if (list.get(i).contains("r"))
{
list.remove(i);
} else if (list.get(i).contains("l"))
{
list.add(list.size()-1,list.get(i));
}
}
return list;
}
}
Upvotes: 0
Views: 87
Reputation: 6818
Instead of messing with loops, iterators and ConcurrentModificationException
s, try to do the steps one by one using streams.
First of all, get rid of strings that contain r, but not l. A simple List#removeIf
method call is enough.
//Remove strings that contain r but not l
list.removeIf(s -> s.contains("r") && !s.contains("l"));
Now lets "clone" strings that contain l, but not r. In order to do that we will filter the list and collect the result into a new list of strings. Then call List#addAll
in order to add them into the original list.
//Find all strings that contain l but not r
List<String> stringsThatContainLButNotR = list.stream().filter(s -> s.contains("l") && !s.contains("r"))
.collect(Collectors.toList());
list.addAll(stringsThatContainLButNotR);
Comple example:
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("rose"); // 0
list.add("love"); // 1
list.add("lyre"); // 2
//Remove strings that contain r but not l
list.removeIf(s -> s.contains("r") && !s.contains("l"));
//Find all strings that contain l but not r
List<String> stringsThatContainsLButNotR = list.stream().filter(s -> s.contains("l") && !s.contains("r"))
.collect(Collectors.toList());
list.addAll(stringsThatContainsLButNotR);
list.forEach(System.out::println);//prints "love","lyre","love"
}
Upvotes: 1
Reputation: 4347
Do not modify (add/remove) the list while iterating. This is applicable to other collection types as well.
Maintain two separate lists - one for elements to be added(addList
) and another for the elements to be removed(removeList
). Finally, from the main list remove the required elements (removeList
) and also add the other required elements (addList
). I have modified your code slightly as described above.
import java.util.ArrayList;
import java.util.List;
public class DuplicateItemInList {
public static void main(String[] args) throws Exception {
ArrayList<String> list = new ArrayList<>();
list.add("rose"); // 0
list.add("love"); // 1
list.add("lyre"); // 2
list = fix(list);
for (String s : list) {
System.out.println(s);
}
}
public static ArrayList<String> fix(ArrayList<String> list) {
List<String> addList = new ArrayList<>();
List<String> removeList = new ArrayList<>();
for (int i = 0; i < list.size(); i++)
{
if (list.get(i).contains("r") && list.get(i).contains("l"))
{
continue;
} else if (list.get(i).contains("r"))
{
removeList.add(list.get(i));
} else if (list.get(i).contains("l"))
{
addList.add(list.get(i));
}
}
list.removeAll(removeList);
list.addAll(addList);
return list;
}
}
Output:
love
lyre
love
Upvotes: 0
Reputation: 201537
First, in main
and in your method program to the List
interface (instead of the ArrayList
concrete type). Also, you can use Arrays.asList
to create your initial list
. Like,
public static void main(String[] args) throws Exception {
List<String> list = new ArrayList<>(Arrays.asList("rose", "love", "lyre"));
list = fix(list);
for (String s : list) {
System.out.println(s);
}
}
Then, in order to avoid a ConcurrentModificationException
you need to use Iterator.remove()
(as the Javadoc notes The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method). And to append create a temporary list of items to append and then append after you traverse the List
. And don't be afraid to store the value
in a temporary variable (list.get(index)
is both tedious and difficult to reason about). Finally, you can save the results of your "contains l" and "contains r" tests with variables as well. Something like,
public static List<String> fix(List<String> list) {
Iterator<String> iter = list.iterator();
List<String> appendList = new ArrayList<>();
while (iter.hasNext()) {
String value = iter.next();
boolean containsR = value.contains("r"), containsL = value.contains("l");
if (containsR && containsL) {
continue;
} else if (containsR) {
iter.remove();
} else if (containsL) {
appendList.add(value);
}
}
list.addAll(appendList);
return list;
}
which outputs
love
lyre
love
Upvotes: 2