2011-11-12 21 views
5

Jaki jest najlepszy sposób na znalezienie i oznaczenie zduplikowanych obiektów w kolekcji? Powiedzmy, że mamy osoby z Listy, a nasza powielona strategia opiera się na dokładnym dopasowaniu imienia i nazwiska.Wyszukiwanie duplikatów w kolekcji

  1. zidentyfikować wszystkie duplikaty
  2. Mark każdego duplikatu wskazując, że jest to duplikat
  3. Dla każdego duplikatu osoby, identyfikacji obiektu jest to duplikat

Czy istnieje prosty sposób to zrobić to z guava?

+0

Czy możesz wyjaśnić, co masz na myśli „identyfikacji obiektu to jest duplikatem "- zakładam, że masz na myśli, że pierwszy element to" prawdziwy "przedmiot, a kolejne elementy są duplikatami? –

Odpowiedz

5

Nie trzeba Guava to zrobić:

List<Person> people = ... 
Map<Name, Person> peopleByName = new HashMap<>(); 
for (Person person : people) { 
    // Name is a simple value class with equality based on its fields 
    Name name = new Name(person.getFirstName(), person.getLastName()); 
    Person firstPersonWithName = peopleByName.get(name); 
    if (firstPersonWithName == null) { 
    peopleByName.put(name, person); 
    } else { 
    // or whatever you do to mark a duplicate 
    person.setDuplicateOf(firstPersonWithName); 
    } 
} 

Powiedział, że można użyć Guava Table zamiast Map i uniknąć konieczności tworzenia Name ... używać imienia jako rzędzie klucze i nazwisko jako klawisze kolumnowe, powiedz.

Innym wyborem byłoby użycie Multimaps.index do zindeksowania wszystkich osób na liście według nazwy. Następnie dla każdej listy osób zmapowanych na konkretną nazwę pierwsza osoba byłaby pierwszą osobą o tej nazwie z listy, a pozostałe byłyby duplikatami.

1

Dlaczego nie spróbować przesłonić .equals() w obiekcie osoby. Następnie dodaj nowe pole do każdego obiektu osoby "duplicateOf" lub coś podobnego.

Następnie wystarczy zapętlić tablicę, sprawdzając każdą osobę przed pozostałymi. Jeśli pole "duplicateOf" osoby ma wartość null, pomiń go. Jeśli .equals() zwraca wartość true, możesz ustawić pole "duplicateOf".

1

Klasa Osoba musi wdrożyć boolean equals(Object o).

Następnie można znaleźć duplikaty w ten sposób:

Musisz gdzieś: Collection<Person> list;

Person[] persons = list.toArray(); 
Integer[] duplicateOf = new Integer[persons.length]; 
Arrays.fill(duplicateOf, -1); 

// For all the values in the Collection 
for (int i = 0; i < persons.length; i++) { 

    // Find the duplicate 
    for (int j = 0; j < persons.length; j++) { 
    if (persons[i].equals(persons[j]) && i != j) 
     duplicateOf[j] = i; 
    } 
} 

Teraz masz Array duplicateOf który można odczytać w ten sposób: Duplikat elementu j jest na indeksie duplicateOf[j].

2

Możesz spróbować użyć Guava's TreeMultimap.

utworzyć nowy TreeMultimap inicjalizacji z komparator do porównywania Ci osoby jak chcesz: TreeMultimap.create(Comparator, Ordering.arbitrary())

Tutaj jest test jednostki:

package org.test.guava; 

import java.util.Arrays; 
import java.util.Comparator; 
import java.util.List; 

import org.junit.Test; 

import com.google.common.collect.Multimap; 
import com.google.common.collect.Ordering; 
import com.google.common.collect.TreeMultimap; 

public class GuavaTest { 

    private static class Person { 
     private String name; 

     public Person(String name) { 
      this.name = name; 
     } 

     public String getName() { 
      return name; 
     } 

     @Override 
     public String toString() { 
      return "Person [name=" + name + "]"; 
     } 

    } 

    @Test 
    public void test() throws Exception { 
     List<Person> persons = Arrays.asList(new Person("person1"), new Person("person2"), new Person("person1")); 
     Comparator<Person> comparator = new Comparator<Person>() { 
      public int compare(Person o1, Person o2) { 
       return o1.getName().compareTo(o2.getName()); 
      } 
     }; 

     Multimap<Person, Person> groups = TreeMultimap.create(comparator, Ordering.arbitrary()); 
     for(Person person : persons) { 
      groups.put(person, person); 
     } 

     System.out.println(groups.asMap()); 
    } 

} 
+0

Jak mogę spełnić wymaganie nr 3 z mojego pytania? –

+0

Odpowiedź została zaktualizowana. Przepraszam, że wprowadzam w błąd multisetami. Spróbuj użyć TreeMultimaps. – szhem

+2

Posługiwanie się posortowaną wieloma mapami jest niepotrzebne i sprawia, że ​​twoje intencje są mniej wyraźne, ponieważ używasz go jako sposobu na wybranie innego klucza równości. Używanie samej nazwy jako klucza jest lepsze. Następnie możesz po prostu użyć 'Multimaps.index'. – ColinD