Reputation: 149
I'm fairly new to Java and I've been trying to solve the following problem unsuccessfully.
Write a Java method that will remove duplicates from a given list.
Assuming:
void
equals()
Main:
removeDuplicates()
, pass in this listI can solve the problem by passing in my list to a new HashSet and copy it back. But the problem is:
equals()...
void
, how can i output it in the main
?import java.util.*; public class Question1 {
public static void main(String[] args) {
String[] words = {"good","better", "best", "best", "first" , "last", "last", "last", "good"};
List<String> list = new ArrayList<String>();
for (String s : words) {
list.add(s);
}
removeDuplicates(list);
}
static void removeDuplicates(List<String> array){
HashSet<String> hs = new HashSet<>();
hs.addAll(array);
array.clear();
array.addAll(hs);
for (String x : array){
System.out.println(x);
}
}
}
EDIT: well, this one works, but as you can see i'm not using equals() and i'm printing out from my static method, not from main. Also, is there any way I can populate the List faster than using String[] ?
Upvotes: 1
Views: 2858
Reputation: 1234
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class Main {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("good");
list.add("better");
list.add("best");
list.add("best");
list.add("first");
list.add("last");
list.add("last");
list.add("last");
list.add("good");
removeDuplicates(list);
System.out.println(list.toString());
}
public static void removeDuplicates(List<String> list) {
if (list != null) {
for (int i = 0; i < list.size(); i++) {
ListIterator<String> listIterator = list.listIterator();
while (listIterator.hasNext()) {
int nextIndex = listIterator.nextIndex();
String nextElement = listIterator.next();
if (list.get(i).equals(nextElement) && i != nextIndex)
listIterator.remove();
}
}
}
}
}
Upvotes: 0
Reputation: 14289
The probably easiest way would be to use a Set in the first place, which by definition does not allow duplicates.
For your actual problem, you can do several approaches:
The easy but slow approach: compare each element A with each other element N in the list. If A.equals(N) remove N. Hint: you only need to compare A to each further element, as you have already checked each element before A.
The faster approach: sort the list using the natural comperator. Now you no longer need to compare each element A vs N, but only A vs the next few elements. To be exact: until you find the first element that is not equal to A. In this case you can assume that there is no further duplicate of A (thanks to the sorting) and continue with this next element as A.
The Map approach (fast but takes more memory): for each element put into the list, put the same element into a Map with any Object as value. Now you can just look-up whether or not that element is already in the map, and if it is, it is a duplicate.
The best way would be the 2nd approach as the sorting is very fast, you only need to get each element once, and there is no 2nd list necessary.
Edit: The 2nd approach in code:
static void removeDuplicates(List<String> array) {
if (array.size() <= 1) {
return;
}
Collections.sort(array);
final Iterator<String> it = array.iterator();
String a = it.next(), n;
while (it.hasNext()) {
n = it.next();
if (((a == null) && (n != null))
|| ((a != null) && (a.equals(n) == false))) {
a = n;
} else {
it.remove();
}
}
}
Upvotes: 1
Reputation: 2068
Here's how you would do the same thing without using a Set
and just using equals()
(also to somewhat answer your "EDIT" question about initializing a List
) :
public static void main(String[] args) {
List<String> list = new ArrayList<String>(Arrays.asList(new String[] {
"good", "better", "best", "best", "first", "last", "last", "last",
"good"}));
removeDuplicates(list);
for (String x : list) {
System.out.println(x);
}
}
static void removeDuplicates(List<String> array) {
for (int i = 0; i < array.size(); i++) {
String next = array.get(i);
// check if this has already appeared before
for (int j = 0; j < i; j++) {
// if it has, stop the search and remove it
if (next.equals(array.get(j))) {
array.remove(i);
// decrement i since we just removed the i'th element
i--;
// stop the search
break;
}
}
}
}
That said, using HashSet
is a better idea since as has already been pointed out it is more efficient.
If you want the efficiency of HashSet
but still preserve the order of the List
you could do something like this :
static void removeDuplicates(List<String> array) {
Set<String> set = new HashSet<String>();
for (int i = 0; i < array.size(); i++) {
String next = array.get(i);
// check if this has already appeared before
if (!set.add(next)) {
// if it has then remove it
array.remove(i);
// decrement i since we just removed the i'th element
i--;
}
}
}
Upvotes: 1
Reputation: 31675
removeDuplicates
creates a set, then iterates over the input list. If it encounters an element in the input list, that is also in the set, removeDuplicates
removes the element from the input list, otherwise it adds the element to the set.removeDuplicates
can modify the List<String> array
that it receives and the caller will see that modified list after the call to removeDuplicates
returned.Upvotes: 2
Reputation: 12206
java.util.HashSet
uses Object.equals(Object)
in its implementation of Set.add(Object)
to determine that the element being inserted is unique (as defined by not being equal to another element). HashSet also has the advantage of allowing you to do the de-duping process in O(n)
time vs a more naive approach of comparing every element to every other element in O(n^2)
time.
The code in main
will see the modified list, because the List object is mutable. When a method changes the state of a passed in argument the calling code will see those changes.
Upvotes: 3