2013-06-03 15 views
6

Trước khi bắt đầu, tôi nghĩ rằng câu hỏi này có một câu trả lời rất đơn giản mà tôi chỉ xem xét. Tôi đã tìm thêm một vài câu hỏi về vấn đề này sẽ có thể chỉ ra vấn đề của tôi khá nhanh.Làm cách nào để xóa các đối tượng trùng lặp khỏi hai ArrayLists riêng biệt?

Tôi có hai ArrayLists mà tôi muốn so sánh và xóa các từ khóa trùng lặp khỏi mỗi người trong số họ. ArrayList đầu tiên là một thông tin cũ hơn ArrayList trong đó ArrayList thứ hai chứa thông tin mới.

Giống như rất

ArrayList<Person> contactList = new ArrayList(); 
contactList.add(new Person("Bob"); 
contactList.add(new Person("Jake"); 
contactList.add(new Person("Joe"); 
ontactList.add(new Person("Rob"); 

ArrayList<Person> updatedContactList = new ArrayList(); 
updatedContactList.add(new Person("Bob"); 
updatedContactList.add(new Person("Jake"); 
updatedContactList.add(new Person("Joe"); 
updatedContactList.add(new Person("Phil"); 

lớp Person của tôi rất đơn giản, được tạo ra chỉ duy nhất cho ví dụ này

public class Person { 
    private String name; 

    public Person(String a_name) { 
     name = a_name; 
    } 

    public String getName() { 
     return name; 
    } 
} 

Vì vậy, sử dụng các ví dụ trên, tôi muốn loại bỏ tất cả các bản sao. Tôi đang cố gắng giữ nó chỉ là hai ArrayLists nếu có thể, nhưng tôi sẵn sàng làm một bản sao sâu của một trong những ArrayLists nếu tôi phải.

Vì vậy, tôi muốn kết quả ArrayList để có các thông tin sau trong nó một lần so sánh được thực hiện

Dưới đây là đoạn code tôi đã đặt cùng

for(int i = 0; i < contactList.size(); i++) { 
    for(int j = 0; j < updatedContactList.size(); j++) { 

     if(contactList.get(i).getName().equals(updatedContactList.get(j).getName())) { 
      //removed friends      
      contactList.remove(contactList.get(i)); 

      //new friends ---- only one at a time works 
      //updatedContactList.remove(updatedContactList.get(j)); 
     } 
    } 
} 

Tôi chỉ có thể để loại bỏ một người khỏi một trong các ArrayLists trong vòng lặp ở trên nếu không tôi nhận được kết quả không chính xác.

Vì vậy, câu hỏi của tôi là, có cách nào dễ dàng để xóa các phần tử trùng lặp khỏi cả hai ArrayLists? Nếu vậy, làm thế nào để tôi đi về nó.

Tôi nhận ra rằng tôi có thể sao chép bản cập nhật ArrayList và chỉ xóa các đối tượng khỏi đó, nhưng tôi tự hỏi liệu có cách nào không phải sao chép nó.

Tôi cũng nhận ra rằng tôi có thể nhồi nhét tất cả các phần tử vào một bộ và nó sẽ loại bỏ các bản sao, nhưng tôi muốn giữ riêng các đối tượng "đã loại bỏ" và "mới".

+0

Tôi giả định rằng các danh sách riêng lẻ sẽ không có bản sao, đúng không? – arshajii

+0

@arshajii Khi so sánh được thực hiện, mỗi danh sách sẽ không chứa bản sao giữa hai người trong số họ. Một ArrayList sẽ chứa 'Person' (s) bị loại bỏ và ArrayList khác sẽ chỉ chứa các đối tượng' Person' mới. – WilliamShatner

+0

Tôi có nghĩa là trước khi tay, trước khi bất cứ điều gì được thực hiện cho hai danh sách. Bạn không thể, ví dụ, có hai 'Bob' trong 'contactList', phải không? – arshajii

Trả lời

6

gì bạn thực sự có không phải là danh sách, nhưng bộ: mô hình cả cũ và địa chỉ liên lạc mới dưới dạng Set. Đồng thời triển khai equalshashCode cho lớp học Person của bạn để đảm bảo hoạt động đúng.

Một khi bạn có điều đó, bạn sẽ có thể viết một lớp lót để tính toán sự khác biệt set (đó là những gì bạn cần):

final Set<Person> contactsBackup = new HashSet<>(contacts); 
contacts.removeAll(updatedContacts); 
updatedContacts.removeAll(contactsBackup); 

Lưu ý rằng điều này liên quan đến việc làm một bản sao hơn, nhưng nó không phải là bản sao sâu — chỉ các tham chiếu được sao chép. Đây là một hoạt động rất nặng và bạn không nên lo lắng về tác động của nó.

Nếu vì một lý do không phải ở tất cả rõ ràng với tôi, bạn thực sự cần danh sách, cùng mã sẽ làm việc cho họ, quá (List cũng định nghĩa removeAll), nhưng bạn sẽ phải sống chung với O (n ) sự phức tạp mà thao tác này đòi hỏi phải có cho các danh sách.

+0

+1. Thời gian chạy của 'List # removeAll (Collection)' thực sự phụ thuộc vào loại bộ sưu tập được chuyển thành tham số. Câu lệnh của bạn là true cho 'list.removeAll (otherList);'. Sau đây sẽ là danh sách 'O (n)': '.removeAll (hashset); ' – jlordo

+0

@MarkoTopolnik Điều này có vẻ giống như một cách đơn giản để thực hiện nó (như phương thức của jLordo), nhưng điều gì sẽ xảy ra nếu tôi muốn sắp xếp danh sách của mình? Ví dụ, khi tôi phân tích chúng ra khỏi xml, chúng xuất hiện theo thứ tự bảng chữ cái. Nhưng nếu sau này tôi quyết định tôi muốn chúng được sắp xếp theo một số thông tin khác nhau trong chúng, nó sẽ là một vấn đề khi chúng là một bộ? – WilliamShatner

+0

@jlordo Vâng, tôi đã không phản đối tuyên bố của bạn cả :) Nhưng tôi đã gặp lỗi trong nhận xét của tôi vì vậy tôi đã xóa nó. Tôi không thể giữ nguyên mã. –

3

Override equals()hashCode() trong lớp Person của bạn và chỉ cần làm:

Set<Person> temp = new HashSet<>(contactList); 
contactList.removeAll(updatedContactList); 
updatedContactList.removeAll(temp); 
temp.clear(); // not necessary if this code is in a method 
+1

Bạn có thể xây dựng một chút không? Tôi giả định cho 'bằng()' Tôi sẽ làm những gì tôi đã làm ở trên (sửa tôi nếu tôi sai). Tôi chưa bao giờ ghi đè 'hashCode()' trước đây. Tôi sẽ làm gì trong phương thức 'hashCode()' bị ghi đè của mình? – WilliamShatner

+1

Bạn đang sử dụng nhật thực? Nếu vậy, hãy nhấp vào 'Nguồn -> Tạo hashCode() và bằng()' – jlordo

+0

Netbeans 7.1 (jdk vẫn ở 6) – WilliamShatner

1

Trong trường hợp này, hãy sử dụng Đặt và không liệt kê (điều này được sử dụng nếu bạn đang nhận dữ liệu từ DB sử dụng nói Hibernate) nếu có thể. Sau đó, bạn có thể ghi đè bằng và phương thức hashcode trong lớp người để có thể thêm các so sánh được yêu cầu và các bản sao có thể được lấy ra. LinkedHashSet có thể được sử dụng làm Danh sách có thể trở nên chậm khi dữ liệu trong đó phát triển.

0

Đây là một dòng giải pháp thanh lịch làm việc sử dụng Java 8 khả năng

public static final <T> void removeCommonEntries(Collection<T> a, Collection<T> b){ 
     b.removeIf(i -> a.remove(i)); 
} 

tôi đặt giải pháp này trong tùy chỉnh của bạn CollectionUtils.