Remove duplicates in ArrayList - Java

2020-05-06 10:53发布

I have some problem with my Java code. I'm supposed to use loops and not any other method. Say that my ArrayList contains of

[Dog Cat Dog Dog Cat Dog Horse]

My goal is also to remove the copies of Dog and Cat so my final results equals

[Dog Cat Horse]

public void removeDouble(){

int counter = 0;
for (int i = 0 ; i < animals.size(); i++) { 
    for (int j = 1+i;  j < animals.size() ; j++)  
        //don't start on the same word or you'll eliminate it.
        if ( animals.get(j).equals( animals.get(i) )  ) {
            animals.remove(animals.get(j));
           counter++;

        }                                
    } 
}

It feels like the "logic" is correct but my code does not work very well. Can somebody help me a little?

8条回答
\"骚年 ilove
2楼-- · 2020-05-06 11:24

You can do like this.

 ArrayList<String>list=new ArrayList<>();
    list.add("A");
      list.add("B");
      list.add("C");
      list.add("A");
    System.out.println("Before "+list); // output[A,B,C,A]


    Set<String> listWithoutDuplicates = new LinkedHashSet<String>(list);
     list.clear();

    list.addAll(listWithoutDuplicates);
    System.out.println("list without duplicates : " + list);// output[A,B,C]
查看更多
仙女界的扛把子
3楼-- · 2020-05-06 11:27

In Java 8 we can use Stream API to remove duplicates, Like below snippet.

List<String> uniqueAnimal = animal.stream().distinct().collect(Collectors.toList()); 

Working Example.

import java.util.*;
import java.util.stream.Collectors;
public class MyClass {
    public static void main(String args[]) {
        List<String> animal = new ArrayList<>();
        animal.add("Dog");
        animal.add("Cat");
        animal.add("Dog");
        animal.add("Dog");
        animal.add("Cat");
        animal.add("Dog");
        animal.add("Horse");
        List<String> uniqueAnimal = animal.stream().distinct().collect(Collectors.toList());
        System.out.println("animal =>  " + animal);
        System.out.println("uniqueAnimal =>  " + uniqueAnimal);
    }
}
查看更多
Bombasti
4楼-- · 2020-05-06 11:30

With Java 8 stream you can do as follows:

public class RemoveDuplicates {

public static void main(String[] args) {
    removeDuplicateElements(Arrays.asList("Dog","Cat","Dog","Dog","Cat","Dog","Horse"));
  }

private static void removeDuplicateElements(List<String> animalList)
  {
    animalList.stream().distinct().collect(Collectors.toList()).forEach(System.out::println);
  }

}
查看更多
做个烂人
5楼-- · 2020-05-06 11:38

It would be simpler to start from the end of the list and decrement the counter. After removing the double at i, we can break without checking the whole string, because further doubles will be detected when i reaches j.

    for(int i=animals.size()-1; i>0; i--) {
        for(int j=i-1; j>=0; j--) {
            if(animals.get(i).equals(animals.get(j))) {
                animals.remove(i);
                break;
            }
        }
    }

Moving backwards avoids the problem as you move forward the indexes have changed because you removed earlier elements (and you failed to adjust the index to take that into account).

Another problem with your logic you were using remove(object) rather than remove(index), which causes the first matching object to be removed. However, based on expected output, you want to preserve the order of the first matching objects. So instead you should have removed the last matching object, via index.


If you want to move forward rather than backwards, but you don't wish to make adjustments to the index after a removal, it is possible to make use of iterator's remove method:

    for(int i=0; i<animals.size()-1; i++) {
        ListIterator<?> iter = animals.listIterator(i+1);
        while(iter.hasNext()) {
            if(animals.get(i).equals(iter.next())) {
                iter.remove();
            }
        }
    }

Unfortunately the outer loop here cannot use an iterator because that would result in a ConcurrentModificationException.


Finally, you could also use a subList to solve it with a single explicit loop:

    for(int i=0; i<animals.size()-1; i++) {
        animals.subList(i+1, animals.size()).removeIf(animals.get(i)::equals);
    }
查看更多
虎瘦雄心在
6楼-- · 2020-05-06 11:38

Your current code -

for (int i = 0; i < animals.size(); i++) {
     for (int j = 1 + i; j < animals.size(); j++)
         if (animals.get(j).equals(animals.get(i))) {
             animals.remove(animals.get(j)); // this would remove the current element only if the previous element is same as the current element
             // since the index `j` would change post that 
         }
     }
}

A simple way to do this is

animals.stream().distinct().collect(Collectors.toList()).forEach(System.out::print);

Or using -

Set<String> distAnimal = new HashSet<>(animals);
System.out.println(Arrays.toString(distAnimal.toArray()));
查看更多
Root(大扎)
7楼-- · 2020-05-06 11:39

Thanks for all the answers. I still have a few problems, this is what i have came up with:

    int counter =0;
for(int i = 0 ; i < animals.size() ; i++){
    for(int j = animals.size() -1 ; j>i ; j--){
        if(animals.get(j).equals(animals.get(i))){
            counter++;

}

    }
}
    System.out.println(counter);
}

So now I'm starting the inner loop from the end of the ArrayList. Priority right now is only the get the loop working and then add remove etc.

Cheers!

查看更多
登录 后发表回答