开发者

Modifying an ArrayList in Java

I want to search through an ArrayLst and delete any entries that are the same.

For example if my list was: apple, orange, banana, pear, peach, orange,

then "orange" would be deleted (both occurances).

Naively, I tried:

开发者_StackOverflow
for(String word : userlist){

for(String otherword : userlist){

...
}
}

where I wrote how to .remove(lastIndexOf(userword)) if it equals word and their indexes are different.

This led to exception after exception, and I quickly realized I was manipulating a list while iterating through it which was making it all go wrong.

So decided to make a copy of the list

ArrayList<String> copylist = userlist;

for(String word : copylist){

    for(String otherword : copylist){

    if(word.equalsIgnoreCase(otherword) 
            && copylist.lastIndexOf(word)!=copylist.lastIndexOf(otherword)){

userlist.remove(userlist.lastIndexOf(word));
userlist.remove(userlist.lastIndexOf(otherword));
    }

    }
    }

SO I tried this, and it had similar problems. Notably ConcurrentModificationException. After tweaking it I can't get, what in my head should be a fairly easy process, to work in Java. Please help.


You're currently not making a copy of the list at all. You're declaring a new variable which has a reference to the same list. To make a copy of the list, use:

ArrayList<String> copyList = new ArrayList<String>(userList);

However, I'd suggest a different approach:

ArrayList<String> wordsToRemove = new ArrayList<String>();
Set<String> seenWords = new HashSet<String>();

for (String word : userList)
{
    if (!seenWords.add(word))
    {
        wordsToRemove.add(word);
    }
}

for (String word : wordsToRemove)
{
    // Keep removing it until it doesn't exist any more
    while (userList.remove(word)) {}
}

This doesn't ignore case, however. To do that, you need to be a bit smarter:

Set<String> wordsToRemove = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
Set<String> seenWords = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);

for (String word : userList)
{
    if (!seenWords.add(word))
    {
        wordsToRemove.add(word);
    }
}

// Now we know the words we don't want, step through the list again and
// remove them (case-insensitively, as wordsToRemove is case-insensitive)
for (Iterator<String> iterator = userList.iterator(); it.hasNext() ;)
{
    if (wordsToRemove.contains(word))
    {
        iterator.remove();
    }
}


import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


public class Test {
    public static void main(String[] args) {
        List<String> a = new ArrayList<String>();
        a.add("apple");
        a.add("orange");
        a.add("banana");
        a.add("pear");
        a.add("peach");
        a.add("orange");
        System.out.println(a);
        System.out.println(getSingleWordList(a));
    }
    private static List<String> getSingleWordList(List<String> list)
    {
        Set<String> uniques = new HashSet<String>();
        Set<String> dups    = new HashSet<String>();

        for (String a : list)
            if (!uniques.add(a))
                dups.add(a);


        uniques.removeAll(dups);

        return new ArrayList<String>(uniques);
    }
}

OUTPUT

Input = [apple, orange, banana, pear, peach, orange]

Output = [pear, apple, banana, peach]


If you wish to remove element during iteration through collection you have to use Iterator and Iterator.remove()

But I'd like to suggest you easier solution: put your list into set. It automatically removes duplicates:

List<String> mylist = new ArrayList<String>();
// some initialization: there are duplicates

Set<String> myset = new HashSet<String>(mylist); // no duplicates here.

You can continue using set because it is collection and you can iterate over it. But if you need random access create list again:

newlist = new ArrayList<String>(myset);

The elements order in set will be "random" as a result of hashing. If you wish to preserve the original order use LinkedHashSet instead of HashSet.


ArrayList<String> copylist = userlist; 

This line assigns the reference userlist to copylist and it does not create new arraylist. It points to same arraylist. To make a new list, simple way is to create entirly new list and keep adding items in this new list after checkin whether item is already present in new list or not.

ArrayList<String> newList = new ArrayList<String> ();

foreach(String item in userList) {
    if(newList.contains(item)==false)
    {
          newList.add(item);
    }
}


It is well known problem - you cannot modify container that is iterated. The trick to resolve is usage of method remove of Iterator:

    Iterator<String> tblIter = array.iterator();
    while (tblIter.hasNext()) {
        String entry = tblIter.next();
        if( entry.equals(.....) )
        {
            ...
            tblIter.remove();
        }
    }


If you have control on how data is added, you might create your own "add" method, something like this:

add(element)
{
    if arrayList.contains(element)
        arrayList.remove(arrayList.indexOf(element))

    else
        arrayList.add(element)
}

on the other hand, if you do not have control on how/when the data is added, you can do a loop and in it have a similar logic as above. Take a look here for the appropriate methods.


If the objective is a collection without duplicate elements, consider whether a Set would be more appropriate than a List.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜