2014-10-31 20 views
6

Sto cercando di ordinare una mappa in base alla frequenza delle parole (ad esempio, in base al valore). Per quello ho un comparatore sovrascritto e passato a TreeMap, ma sto ottenendo questo output strano.Mentre si ordina la mappa in base al valore, mancano alcuni valori. Cosa causa questo strano comportamento?

public class WordFrequency { 
    public static String sentence = "one three two two three three four four four"; 
    public static Map<String, Integer> map; 

    public static void main(String[] args) { 
     map = new HashMap<>(); 
     String[] words = sentence.split("\\s"); 

     for (String word : words) { 
      Integer count = map.get(word); 
      if (count == null) { 
       count = 1; 
      } else { 
       ++count; 
      } 
      map.put(word, count); 
     } 

     Comparator<String> myComparator = new Comparator<String>() { 

      @Override 
      public int compare(String s1, String s2) { 
       if (map.get(s1) < map.get(s2)) { 
        return -1; 
       } else if (map.get(s1) > map.get(s2)) { 
        return 1; 
       } else { 
        return 0; 
       } 
      } 

     }; 
     SortedMap<String, Integer> sortedMap = new TreeMap<String, Integer>(myComparator); 
     System.out.println("Before sorting: " + map); 
     sortedMap.putAll(map); 
     System.out.println("After Sorting based on value:" + sortedMap); 

    } 
} 

Uscita: Uscita

Before sorting: {two=2, one=1, three=3, four=3} 
After sorting based on value:{one=1, two=2, three=3} 

atteso:

{one=1, two=2, four=3,three=3} 
+0

Cosa c'è di strano in questo? –

+0

Eventualmente TreeMap non consente duplicati –

+0

@SotiriosDelimanolis four = 3 manca dopo l'ordinamento –

risposta

5

Il metodo compare non rispetta il contratto dell'interfaccia Mappa, poiché confronta i valori anziché le chiavi. L'implementazione fa sì che due chiavi con lo stesso valore siano considerate la stessa chiave. Pertanto il tuo sortedMap non contiene la chiave "quattro", che ha lo stesso valore del tasto "tre".

Nota che l'ordinamento mantenuto da una mappa ad albero, come qualsiasi mappa ordinata, e se non un comparatore esplicita è fornita, deve essere coerente con eguali se questa mappa ordinato è quello di attuare correttamente l'interfaccia Map. (Vedi Comparabile o Comparatore per una definizione precisa di coerente con uguale.) Questo perché l'interfaccia Mappa è definita in termini dell'operazione equals, ma una mappa ordinata esegue tutti i confronti chiave utilizzando il suo metodo compareTo (o confronta), quindi due chiavi che sono considerate uguali con questo metodo sono, dal punto di vista della mappa ordinata, uguali a. Il comportamento di una mappa ordinata è ben definito anche se il suo ordinamento è incoerente con gli uguali; semplicemente non riesce a rispettare il contratto generale dell'interfaccia Mappa.

TreeMap reference

È possibile risolvere questo problema confrontando i tasti quando i valori sono uguali:

Comparator<String> myComparator = new Comparator<String>() { 

     @Override 
     public int compare(String s1, String s2) { 
      if (map.get(s1) < map.get(s2)) { 
       return -1; 
      } else if (map.get(s1) > map.get(s2)) { 
       return 1; 
      } else { 
       return s1.compareTo(s2); 
      } 
     } 

    }; 

Questo dovrebbe dare un output di:

After sorting based on value:{one=1, two=2, four=3, three=3} 

Dal four<three basato sull'ordinamento naturale delle stringhe.

4

A causa della tua compare() è prendere in considerazione i valori solo nel Map. Quindi lo three=3, four=3 ha lo stesso valore 3. Quindi quelli considerano duplicati quando si aggiungono a TreeMap.

1

Questo perché la tua implementazione sta dicendo a TreeMap che la mappa [tre] e la mappa [quattro] sono essenzialmente lo stesso elemento, perché sono "uguali" tra loro in base al tuo comparatore.

Change "return 0" in Comparatore di "ritorno s1.compareTo (s2)", e avrete

Before sorting: {two=2, one=1, three=3, four=3} 
After Sorting based on value:{one=1, two=2, four=3, three=3} 

(credo che si può capire perché "quattro" viene prima di "tre" in questo caso)

+0

Grazie a @mindex l'ho capito. –