J.Harebell
J.Harebell

Reputation: 25

Remove duplicates in ArrayList - Java

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?

Upvotes: 0

Views: 17456

Answers (8)

Akshay Malapure
Akshay Malapure

Reputation: 84

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);
  }

}

Upvotes: 1

RAGINROSE
RAGINROSE

Reputation: 724

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);
    }
}

Upvotes: 1

J.Harebell
J.Harebell

Reputation: 25

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!

Upvotes: 0

Lovekush Vishwakarma
Lovekush Vishwakarma

Reputation: 3169

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]

Upvotes: 5

Patrick Parker
Patrick Parker

Reputation: 4959

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);
    }

Upvotes: 1

Naman
Naman

Reputation: 31878

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()));

Upvotes: 0

camickr
camickr

Reputation: 324118

The logic for the inner loop is incorrect.

You will skip items every time you have the same item appear consecutively in the list.

Say you had "dog", "dog", "dog", "cat". When you remove the "dog" at index 1, the list now becomes "dog", "dog", "cat".

The problem is that your "j" index is now incremented to 2 so the next test will access the "cat" item, not the "dog" item. So every time you remove an item you are skipping the next item in the list which is why you get inconsistent results.

The solution is to either:

  1. decrement the j variable every time you remove an item
  2. start the inner loop from the end of the list and count down backwards toward 0.

Upvotes: 2

joshua gollaher
joshua gollaher

Reputation: 31

Your removing the items as you are iterating over them, have an array that holds indexes, and when you find a double, add the index to the indexes array. Iterate over the indexes array and delete from the animals arraylist.

Upvotes: 0

Related Questions