2012-05-25 77 views
10

Có công cụ hoặc thư viện nào để tìm các mục nhập trùng lặp trong Bộ sưu tập theo các tiêu chí cụ thể có thể được triển khai không?Tìm các mục trùng lặp trong Bộ sưu tập


Để làm rõ bản thân: Tôi muốn so sánh các mục nhập với nhau theo tiêu chí cụ thể. Vì vậy, tôi nghĩ rằng Predicate chỉ trả lại true hoặc false là không đủ.


Tôi không thể sử dụng equals.

+1

Bạn muốn chỉ định tiêu chí trùng lặp theo cách nào? Là một vị từ nhị phân? – NPE

+1

Bạn có muốn * tìm * các từ khóa trùng lặp hoặc xóa * chúng không? –

+0

@ AndyThomas-Cramer Trên thực tế nó sẽ là đủ chỉ để biết nếu có bản sao. –

Trả lời

2

Tôi đã tạo giao diện mới tương tự như giao diện IEqualityComparer<T> trong .NET.

Như vậy, EqualityComparator<T> Sau đó, tôi chuyển sang phương pháp sau để phát hiện trùng lặp.

public static <T> boolean hasDuplicates(Collection<T> collection, 
     EqualsComparator<T> equalsComparator) { 
    List<T> list = new ArrayList<>(collection); 
    for (int i = 0; i < list.size(); i++) { 
     T object1 = list.get(i); 
     for (int j = (i + 1); j < list.size(); j++) { 
      T object2 = list.get(j); 
      if (object1 == object2 
        || equalsComparator.equals(object1, object2)) { 
       return true; 
      } 
     } 
    } 
    return false; 
} 

Bằng cách này tôi có thể tùy chỉnh so sánh với nhu cầu của mình.

2

Bạn có thể sử dụng bản đồ và trong khi lặp qua bộ sưu tập để đưa các phần tử vào bản đồ (các biến vị ngữ sẽ tạo khóa) và nếu có mục nhập bạn đã tìm thấy một bản sao.

Để biết thêm thông tin xem tại đây: Finding duplicates in a collection

7

Nó phụ thuộc vào ngữ nghĩa của các tiêu chí:

Nếu tiêu chí của bạn luôn luôn là như nhau cho một lớp học nào đó, và là vốn có khái niệm cơ bản, bạn chỉ nên triển khai equalshashCode và sử dụng tập hợp.

Nếu tiêu chí của bạn phụ thuộc vào bối cảnh, org.apache.commons.collections.CollectionUtils.select(java.util.Collection, org.apache.commons.collections.Predicate) có thể là giải pháp phù hợp với bạn.

+0

Tôi muốn so sánh các mục nhập giữa các mục khác, chứ không phải các tiêu chí tùy ý. –

4

Nếu bạn muốn tìm thấy trùng lặp, thay vì chỉ xóa chúng, một cách tiếp cận sẽ là ném Bộ sưu tập vào một mảng, sắp xếp mảng thông qua một Trình so sánh thực hiện tiêu chí của bạn, sau đó đi thẳng qua mảng, tìm kiếm cho các bản sao liền kề.

Dưới đây là một phác thảo (không kiểm tra):

MyComparator myComparator = new MyComparator(); 
    MyType[] myArray = myList.toArray(); 
    Arrays.sort(myArray, myComparator); 
    for (int i = 1; i < myArray.length; ++i) { 
     if (0 == myComparator.compare(myArray[i - 1], myArray[i])) { 
     // Found a duplicate! 
     } 
    } 

Edit: Từ nhận xét của bạn, bạn chỉ muốn biết nếu có bản sao. Cách tiếp cận ở trên cũng hoạt động cho điều này. Nhưng bạn có thể đơn giản chỉ cần tạo một java.util.SortedSet với một Comparator tùy chỉnh. Dưới đây là một phác thảo:

MyComparator myComparator = new MyComparator(); 
    TreeSet treeSet = new TreeSet(myComparator); 
    treeSet.addAll(myCollection); 
    boolean containsDuplicates = (treeSet.size() != myCollection.size()); 
3

Bạn có thể thích nghi với một tập Java để tìm kiếm các bản sao giữa các đối tượng của một kiểu bất kỳ: quấn lớp mục tiêu của bạn trong một wrapper tin rằng đánh giá bình đẳng dựa trên tiêu chí của bạn, và xây dựng một bộ giấy gói .

Đây là ví dụ hơi dài minh họa kỹ thuật. Nó xem xét hai người có cùng tên giống nhau, và vì vậy nó phát hiện ba bản sao trong mảng năm đối tượng.

import java.util.*; 
import java.lang.*; 

class Main { 
    static class Person { 
     private String first; 
     private String last; 
     public String getFirst() {return first;} 
     public String getLast() {return last;} 
     public Person(String f, String l) { 
      first = f; 
      last = l; 
     } 
     public String toString() { 
      return first+" "+last; 
     } 
    } 
    public static void main (String[] args) throws java.lang.Exception { 
     List<Person> people = new ArrayList<Person>(); 
     people.add(new Person("John", "Smith")); 
     people.add(new Person("John", "Scott")); 
     people.add(new Person("Jack", "First")); 
     people.add(new Person("John", "Walker")); 
     people.add(new Person("Jack", "Black")); 
     Set<Object> seen = new HashSet<Object>(); 
     for (Person p : people) { 
      final Person thisPerson = p; 
      class Wrap { 
       public int hashCode() { return thisPerson.getFirst().hashCode(); } 
       public boolean equals(Object o) { 
        Wrap other = (Wrap)o; 
        return other.wrapped().getFirst().equals(thisPerson.getFirst()); 
       } 
       public Person wrapped() { return thisPerson; } 
      }; 
      Wrap wrap = new Wrap(); 
      if (seen.add(wrap)) { 
       System.out.println(p + " is new"); 
      } else { 
       System.out.println(p + " is a duplicate"); 
      } 
     } 
    } 
} 

Bạn có thể chơi với ví dụ này trên ideone [link].

+0

+1: thú vị! Chỉ cần không có ý tưởng về hiệu quả. – dragon66

+0

@ dragon66 Nếu hàm băm của bạn tốt, hiệu quả cũng giống như với bất kỳ bảng băm nào, là 'O (1)' cho mỗi mục, hoặc 'O (N)' cho toàn bộ bộ sưu tập. – dasblinkenlight

+0

dasblinkenlight: Tôi hơi lo ngại về việc tạo đối tượng bọc mặc dù tôi biết rằng chúng sẽ biến mất bên ngoài vòng lặp. – dragon66

-2

Lặp lại số ArrayList có chứa các bản sao và thêm chúng vào HashSet. Khi phương thức thêm trả về false trong HashSet, chỉ cần đăng nhập bản sao vào bàn điều khiển.

+1

Như OP nói, anh ta không thể sử dụng 'equals()'. Một 'HashSet' sử dụng' hashCode() 'và' equals() '. Do đó anh ta không thể sử dụng một 'HashSet'. –

0

TreeSet cho phép bạn làm điều này một cách dễ dàng:

Set uniqueItems = new TreeSet<>(yourComparator); 
List<?> duplicates = objects.stream().filter(o -> !uniqueItems.add(o)).collect(Collectors.toList()); 

yourComarator được sử dụng khi gọi uniqueItems.add(o), có thêm mục vào tập và trả true nếu mục là duy nhất. Nếu trình so sánh xem mục trùng lặp, add(o) sẽ trả về false.

Lưu ý rằng phương thức equals của mặt hàng phải nhất quán với yourComarator theo the TreeSet documentation để tính năng này hoạt động.

Các vấn đề liên quan