2012-04-16 21 views
12

Zanim opublikuję to pytanie, znalazłem w jakiś sposób podobne pytanie opublikowane here. Ale odpowiedź była oparta na łańcuchu. Jednak mam tu inną sytuację. Nie próbuję usunąć String, ale innego obiektu o nazwie AwardYearSource. Ta klasa ma atrybut int zwany rokiem. Dlatego chcę usunąć duplikaty na podstawie roku. np. jeśli istnieje rok 2010 wspomniany więcej niż jeden raz, chcę usunąć ten obiekt AwardYearSource. Jak mogę to zrobić?Jak usunąć duplikaty z listy na podstawie niestandardowego obiektu java, a nie typu pierwotnego?

+0

Java 8 way jest również całkiem niezły: http://stackoverflow.com/questions/23699371/java-8-distinct-by-property – JDC

Odpowiedz

45

Najprostszym sposobem usunięcia elementów w oparciu o pole jest następująco (kolejność zachowanie):

Map<Integer, AwardYearSource> map = new LinkedHashMap<>(); 
for (AwardYearSource ays : list) { 
    map.put(ays.getYear(), ays); 
} 
list.clear(); 
list.addAll(map.values()); 
+1

Dziękuję. Rozwiązał mój problem. Jednak zmieniłem pierwszą linię twojego kodu na Map map = new LinkedHashMap (); .... inaczej nie będzie się kompilować. – WowBow

+5

Niestety, składnia '<>' działa tylko w języku Java 7. –

+0

Dobra sztuczka. Dzięki, rozwiąż mój problem. – James

0

Można korzystać z mapy i przechowywania przedmiotów z roku jako kluczowy:

Map<Integer, AwardYearSource> map = new HashMap<Integer, AwardYearSource>(); 
map.put(someAwardYearSource1.getYear(), someAwardYearSource1); 
map.put(someAwardYearSource2.getYear(), someAwardYearSource2); 

etc. 

Pod koniec mapa będzie zawierać unikatowe wartości przez rok, co można nazwać metodą wartości:

Collection<AwardYearSource> noDups = map.values(); 
0

Utwórz obiekt HashMap z int jako typem klucza i klasą jako typem wartości. Następnie iteracyjne nad listy i wstawić każdy element na mapie przy użyciu:

mymap.put(source.year, source); 

następnie usunąć wszystkie elementy z listy origianl i iteracyjne nad mapą i włożyć każdy element do listy.

+0

Naprawdę? Czy mógłbyś podać więcej szczegółów? Chociaż co najmniej jeden z iteratorów jest niepotrzebny - zobacz niektóre z innych odpowiedzi. Miałoby to nieprzyjemne skutki uboczne, gdyby były używane w kontekście wątkowym. –

+0

Może ten komentarz został wysłany po błędnej odpowiedzi? Nie widzę żadnych iteratorów w moich rozwiązaniach i jest to bezpieczne dla wątków. – smichak

+0

Jednoznacznie wspomniano o iteracji i użyjecie co najmniej jednego iteratora _implicit_ (generowany kompilator, w przypadku konstruktora for-each). Jeśli jest to pakowane w jego własną metodę (która powinna być), to usuwanie elementów z oryginalnej listy jest ** absolutnie NIE ** Threadafe. –

1

Innym sposobem jest przesłonięcie obiektu hashCode() i equals(Object obj). Ponieważ ma tylko jedno pole, którego chcesz użyć do określenia równości, jest to całkiem proste. Coś jak:

public boolean equals(Object obj) { 
    if (obj == null || !(obj instanceof AwardYearSource)) { 
    return false; 
    } 
    return (this.year == ((AwardYearSource)obj).year); 
} 
public int hashCode() { 
    return this.year; 
} 

Następnie można po prostu trzymać wszystkich obiektów w Set usunąć duplikaty:

Set<AwardYearSource> set = new Set<AwardYearSource>(); 

set.add(new AwardYearSource(2011)); 
set.add(new AwardYearSource(2012)); 
set.add(new AwardYearSource(2011)); 

for (AwardYearSource aws : set) { 
    System.out.println(aws.year); 
} 
0

Jeśli przesłonięcia klasy AwardYearSource równa i metody hashcode (Eclipse może generować zarówno), a następnie możesz dodać je do zestawu. Zestaw nie będzie zawierał żadnych duplikatów.

public class AwardYearSource 
{ 
    private final int year; 

    public AwardYearSource(int year) 
    { 
     this.year = year; 
    } 

    @Override 
    public int hashCode() 
    { 
     final int prime = 31; 
     int result = 1; 
     result = prime * result + year; 
     return result; 
    } 

    @Override 
    public boolean equals(Object obj) 
    { 
     if (this == obj) 
      return true; 
     if (obj == null) 
      return false; 
     if (getClass() != obj.getClass()) 
      return false; 
     AwardYearSource other = (AwardYearSource) obj; 
     if (year != other.year) 
      return false; 
     return true; 
    } 

    @Override 
    public String toString() 
    { 
     return String.valueOf(year); 
    } 


    public static void main(String[] args) 
    { 
     Set<AwardYearSource> set = new HashSet<AwardYearSource>(); 
     set.add(new AwardYearSource(2000)); 
     set.add(new AwardYearSource(2000)); 
     set.add(new AwardYearSource(2000)); 
     set.add(new AwardYearSource(2000)); 

     System.out.println(set); 
    } 
} 

Dane wyjściowe to [2000]. Tylko jeden przedmiot w zestawie.

1

Po prostu. Wprawdzie coś wprawia mnie w błąd co do wersji mapy (nie, że wątpię, żeby zadziałały, to po prostu wydaje się przesadą, jakoś - choć ta wersja niekoniecznie jest lepsza pod tym względem).
Odpowiedź jest funkcjonalna i wątkowo bezpieczny (zakładając, że AwardYearSource jest niezmienny).

public static List<AwardYearSource> removeDuplicateYears(
              final Collection<AwardYearSource> awards) { 
    final ArrayList<AwardYearSource> input = new ArrayList<AwardYearSource>(awards); 
    // If there's only one element (or none), guaranteed unique. 
    if (input.size() <= 1) { 
     return input; 
    } 
    final HashSet<Integer> years = new HashSet<Integer>(input.size(), 1); 
    final Iterator<AwardYearSource> iter = input.iterator(); 
    while(iter.hasNext()) { 
     final AwardYearSource award = iter.next(); 
     final Integer year = award.getYear(); 
     if (years.contains(year)) { 
      iter.remove(); 
     } else { 
      years.add(year); 
     } 
    } 
    return input;  

} 
+0

Zbyt wiele finałów –

0
Set<Integer> set = new HashSet<>(); 
list.removeIf(i -> set.contains(i.getYear()) ? true : !set.add(i.getYear())); 

powinno pomóc w którym kopiowanie jest ustalona na podstawie danej właściwości (lub kombinacji właściwości) lata w tym przypadku. Mam nadzieję że to pomoże.

Powiązane problemy