karina
karina

Reputation: 41

Duplicating items in arraylist

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

Answers (3)

George Z.
George Z.

Reputation: 6818

Instead of messing with loops, iterators and ConcurrentModificationExceptions, 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

fiveobjects
fiveobjects

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

Elliott Frisch
Elliott Frisch

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

Related Questions