วิธีการลบค่าซ้ำ (duplicates) จาก List ใน Java มีหลายวิธี ขึ้นอยู่กับ Java version และ requirement (preserve order หรือไม่)
วิธีที่ 1: ใช้ LinkedHashSet (Java 1.4+) - Preserve Order
แนะนำสำหรับ general use - รักษาลำดับการ insert
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.Set;
public class Demo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Jacob");
list.add("Gary");
list.add("Gary"); // duplicate
list.add("Harry");
list.add("Harry"); // duplicate
list.add("Kevin");
System.out.println("Original List = " + list);
// LinkedHashSet รักษาลำดับ insertion order
Set<String> set = new LinkedHashSet<>(list);
System.out.println("After removing duplicates = " + set);
// [Jacob, Gary, Harry, Kevin]
}
}
Output
Original List = [Jacob, Gary, Gary, Harry, Harry, Kevin] After removing duplicates = [Jacob, Gary, Harry, Kevin]
วิธีที่ 2: ใช้ Stream.distinct() (Java 8+) - Preserve Order
Functional style, ใช้กับ List ใดๆ ได้
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Demo {
public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList(
"Ryan", "Kevin", "Ryan", "Harry", "Mark", "Mark"
));
System.out.println("Original ArrayList = " + list);
List<String> distinctList = list.stream()
.distinct()
.collect(Collectors.toList());
System.out.println("Updated ArrayList without duplicates = " + distinctList);
// [Ryan, Kevin, Harry, Mark]
}
}
Output
Original ArrayList = [Ryan, Kevin, Ryan, Harry, Mark, Mark] Updated ArrayList without duplicates = [Ryan, Kevin, Harry, Mark]
วิธีที่ 3: ใช้ HashSet (ไม่รักษาลำดับ) - Fastest
import java.util.*;
public class HashSetDemo {
public static void main(String[] args) {
List<String> list = Arrays.asList("A", "B", "A", "C", "B");
// ไม่รักษาลำดับ แต่เร็วกว่า
Set<String> set = new HashSet<>(list);
List<String> unique = new ArrayList<>(set);
System.out.println(unique); // ลำดับไม่คงที่ เช่น [A, B, C]
}
}
วิธีที่ 4: In-place Removal (ไม่สร้าง List ใหม่)
import java.util.*;
public class InPlaceDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "A", "C", "B"));
// ใช้ Iterator เพื่อหลีกเลี่ยง ConcurrentModificationException
Set<String> seen = new HashSet<>();
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if (!seen.add(s)) { // add คืน false ถ้ามีอยู่แล้ว
it.remove();
}
}
System.out.println(list); // [A, B, C] - รักษาลำดับ first occurrence
}
}
วิธีที่ 5: ใช้ TreeSet (Sorted + Unique)
import java.util.*;
public class TreeSetDemo {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(5, 2, 8, 2, 5, 1, 9);
// Sorted + Unique
Set<Integer> sortedUnique = new TreeSet<>(list);
System.out.println(sortedUnique); // [1, 2, 5, 8, 9]
}
}
สำหรับ Custom Objects - ต้อง Implement equals() และ hashCode()
import java.util.*;
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person p = (Person) o;
return age == p.age && Objects.equals(name, p.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return name + "(" + age + ")";
}
}
public class CustomObjectDemo {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Alice", 25), // duplicate
new Person("Charlie", 25)
);
List<Person> unique = people.stream()
.distinct() // ใช้ equals/hashCode
.collect(Collectors.toList());
System.out.println(unique); // [Alice(25), Bob(30), Charlie(25)]
}
}
ตารางเปรียบเทียบวิธีต่างๆ
| วิธี | Preserve Order | Null Safe | Performance | Java Version |
|---|---|---|---|---|
| LinkedHashSet | ✅ ใช่ | ✅ ใช่ | O(n) | 1.4+ |
| Stream.distinct() | ✅ ใช่ | ✅ ใช่ | O(n) | 8+ |
| HashSet | ❌ ไม่ | ✅ ใช่ | O(n) เร็วที่สุด | 1.2+ |
| TreeSet | ✅ Sorted | ❌ ไม่ (null ไม่ได้) | O(n log n) | 1.2+ |
| In-place Iterator | ✅ ใช่ | ✅ ใช่ | O(n) | 1.2+ |
ข้อควรระวัง
- Mutable objects: หาก object เปลี่ยนค่าหลัง add เข้า Set อาจทำให้ hashCode เปลี่ยน → duplicate ไม่ถูกลบ
- Null elements: HashSet, LinkedHashSet รองรับ null (1 ตัว) แต่ TreeSet ไม่รองรับ
- Performance: สำหรับ list ใหญ่มาก พิจารณา
Stream.parallel()หรือ database distinct