2010-09-13 14 views
7

Ho un elenco di array che contiene oggetti Quote. Voglio essere in grado di ordinare alfabeticamente per nome, per modifica e per variazione percentuale. Come posso ordinare il mio arraylist?Come ordinare un ArrayList utilizzando più criteri di ordinamento?

package org.stocktwits.model; 

import java.io.Serializable; 
import java.text.DecimalFormat; 

    public class Quote implements Serializable { 

     private static final long serialVersionUID = 1L; 

     public String symbol; 
     public String name; 
     public String change; 
     public String percentChange; 
     public String open; 
     public String daysHigh; 
     public String daysLow; 
     public String dividendYield; 
     public String volume; 
     public String averageDailyVolume; 
     public String peRatio; 
     public String marketCapitalization; 
     public String yearHigh; 
     public String yearLow; 
     public String lastTradePriceOnly; 
     public DecimalFormat df = new DecimalFormat("#,###,###,###,###,##0.00"); 
     public DecimalFormat vf = new DecimalFormat("#,###,###,###,###,##0"); 

     public String getSymbol() { 
      return symbol; 
     } 
     public void setSymbol(String symbol) { 
      this.symbol = symbol; 
     } 
     public String getName() { 
      return name; 
     } 
     public void setName(String name) { 
      this.name = name; 
     } 
     public String getChange() { 
      return change; 
     } 
     public void setChange(String change) { 
      if(change.equals("null")){ 
       this.change = "N/A"; 
      } 
      else{ 
       float floatedChange = Float.valueOf(change); 
       this.change = (df.format(floatedChange)); 
      } 
     } 
     public String getPercentChange() { 
      return percentChange; 
     } 
     public void setPercentChange(String percentChange) { 
      if(percentChange.equals("null")) 
       percentChange = "N/A"; 
      else 
       this.percentChange = percentChange; 
     } 
     public String getOpen() { 
      return open; 
     } 
     public void setOpen(String open) { 
      if(open.equals("null")) 
       this.open = "N/A"; 
      else 
       this.open = open; 
     } 
     public String getDaysHigh() { 
      return daysHigh; 
     } 
     public void setDaysHigh(String daysHigh) { 
      if(daysHigh.equals("null")) 
       this.daysHigh = "N/A"; 
      else{ 
       float floatedDaysHigh = Float.valueOf(daysHigh); 
       this.daysHigh = (df.format(floatedDaysHigh)); 
      } 
     } 
     public String getDaysLow() { 
      return daysLow; 
     } 
     public void setDaysLow(String daysLow) { 
      if(daysLow.equals("null")) 
       this.daysLow = "N/A"; 
      else{ 
       float floatedDaysLow = Float.valueOf(daysLow); 
       this.daysLow = (df.format(floatedDaysLow)); 
      } 
     } 
     public String getVolume() { 
      return volume; 
     } 
     public void setVolume(String volume) { 
      if(volume.equals("null")){ 
       this.volume = "N/A"; 
      } 
      else{ 
       float floatedVolume = Float.valueOf(volume); 
       this.volume = (vf.format(floatedVolume)); 
      } 
     } 
     public String getDividendYield() { 
      return dividendYield; 
     } 
     public void setDividendYield(String dividendYield) { 
      if(dividendYield.equals("null")) 
       this.dividendYield = "N/A"; 
      else 
       this.dividendYield = dividendYield; 
     } 
     public String getAverageDailyVolume() { 
      return averageDailyVolume; 
     } 
     public void setAverageDailyVolume(String averageDailyVolume) { 
      if(averageDailyVolume.equals("null")){ 
       this.averageDailyVolume = "N/A"; 
      } 
      else{ 
       float floatedAverageDailyVolume = Float.valueOf(averageDailyVolume); 
       this.averageDailyVolume = (vf.format(floatedAverageDailyVolume)); 
      } 
     } 
     public String getPeRatio() { 
      return peRatio; 
     } 
     public void setPeRatio(String peRatio) { 
      if(peRatio.equals("null")) 
       this.peRatio = "N/A"; 
       else 
      this.peRatio = peRatio; 
     } 
     public String getMarketCapitalization() { 
      return marketCapitalization; 
     } 
     public void setMarketCapitalization(String marketCapitalization) { 
      if(marketCapitalization.equals("null")) 
       this.marketCapitalization = "N/A"; 
      else 
       this.marketCapitalization = marketCapitalization; 
     } 
     public String getYearHigh() { 
      return yearHigh; 
     } 
     public void setYearHigh(String yearHigh) { 
      if(yearHigh.equals("null")) 
       this.yearHigh = "N/A"; 
      else 
       this.yearHigh = yearHigh; 
     } 
     public String getYearLow() { 
      return yearLow; 
     } 
     public void setYearLow(String yearLow) { 
      if(yearLow.equals("null")) 
       this.yearLow = "N/A"; 
      else 
       this.yearLow = yearLow; 
     } 

     public String getLastTradePriceOnly() { 
      return lastTradePriceOnly; 
     } 

     public void setLastTradePriceOnly(String lastTradePriceOnly) { 
      if(lastTradePriceOnly.equals("null")){ 
       this.lastTradePriceOnly = "N/A"; 
      } 
      else{ 
       float floatedLastTradePriceOnly = Float.valueOf(lastTradePriceOnly); 
       this.lastTradePriceOnly = (df.format(floatedLastTradePriceOnly)); 
      } 
     } 

     @Override 
     public int hashCode() { 
      final int prime = 31; 
      int result = 1; 
      result = prime * result + ((change == null) ? 0 : change.hashCode()); 
      result = prime * result 
        + ((daysHigh == null) ? 0 : daysHigh.hashCode()); 
      result = prime * result + ((daysLow == null) ? 0 : daysLow.hashCode()); 
      result = prime 
        * result 
        + ((lastTradePriceOnly == null) ? 0 : lastTradePriceOnly 
          .hashCode()); 
      result = prime 
        * result 
        + ((marketCapitalization == null) ? 0 : marketCapitalization 
          .hashCode()); 
      result = prime * result + ((name == null) ? 0 : name.hashCode()); 
      result = prime * result + ((open == null) ? 0 : open.hashCode()); 
      result = prime * result + ((peRatio == null) ? 0 : peRatio.hashCode()); 
      result = prime * result 
        + ((percentChange == null) ? 0 : percentChange.hashCode()); 
      result = prime * result + ((symbol == null) ? 0 : symbol.hashCode()); 
      result = prime * result + ((volume == null) ? 0 : volume.hashCode()); 
      result = prime * result 
        + ((yearHigh == null) ? 0 : yearHigh.hashCode()); 
      result = prime * result + ((yearLow == null) ? 0 : yearLow.hashCode()); 
      return result; 
     } 
     @Override 
     public boolean equals(Object obj) { 
      if (this == obj) 
       return true; 
      if (obj == null) 
       return false; 
      if (getClass() != obj.getClass()) 
       return false; 
      Quote other = (Quote) obj; 
      if (change == null) { 
       if (other.change != null) 
        return false; 
      } else if (!change.equals(other.change)) 
       return false; 
      if (daysHigh == null) { 
       if (other.daysHigh != null) 
        return false; 
      } else if (!daysHigh.equals(other.daysHigh)) 
       return false; 
      if (daysLow == null) { 
       if (other.daysLow != null) 
        return false; 
      } else if (!daysLow.equals(other.daysLow)) 
       return false; 
      if (lastTradePriceOnly == null) { 
       if (other.lastTradePriceOnly != null) 
        return false; 
      } else if (!lastTradePriceOnly.equals(other.lastTradePriceOnly)) 
       return false; 
      if (marketCapitalization == null) { 
       if (other.marketCapitalization != null) 
        return false; 
      } else if (!marketCapitalization.equals(other.marketCapitalization)) 
       return false; 
      if (name == null) { 
       if (other.name != null) 
        return false; 
      } else if (!name.equals(other.name)) 
       return false; 
      if (open == null) { 
       if (other.open != null) 
        return false; 
      } else if (!open.equals(other.open)) 
       return false; 
      if (peRatio == null) { 
       if (other.peRatio != null) 
        return false; 
      } else if (!peRatio.equals(other.peRatio)) 
       return false; 
      if (percentChange == null) { 
       if (other.percentChange != null) 
        return false; 
      } else if (!percentChange.equals(other.percentChange)) 
       return false; 
      if (symbol == null) { 
       if (other.symbol != null) 
        return false; 
      } else if (!symbol.equals(other.symbol)) 
       return false; 
      if (volume == null) { 
       if (other.volume != null) 
        return false; 
      } else if (!volume.equals(other.volume)) 
       return false; 
      if (yearHigh == null) { 
       if (other.yearHigh != null) 
        return false; 
      } else if (!yearHigh.equals(other.yearHigh)) 
       return false; 
      if (yearLow == null) { 
       if (other.yearLow != null) 
        return false; 
      } else if (!yearLow.equals(other.yearLow)) 
       return false; 
      return true; 
     } 
    } 
+0

Odio davvero le classi come questa. Le classi hanno bisogno di avere una vera logica di business per cui valga la pena - preferisco usare qualcosa sulla falsariga degli hash per cose come questa. A lungo andare usare una classe come un sacco di attributi diventa solo fastidioso. La ripetitività dovrebbe mostrare che è ovviamente sbagliato. Alcune persone considerano questo come un difetto di Java, io tendo a pensare che sia più una colpa dei programmatori che non sono disposti a espandersi. L'ho fatto in modi che consentivano la convalida, la sicurezza del tipo e molti altri trucchi. Nessun codice standard, ma è stato un sacco di lavoro - ne vale la pena anche se - boilerplate fa schifo. –

+6

non sono sicuro di essere completamente d'accordo, ma una cosa mi colpisce: ci sono tutti questi metodi setter e getter, ma i campi che ottengono/sono tutti pubblici! Quelli dovrebbero essere privati –

risposta

9

Creare un appropriato Comparator che confronterà due elementi in base ai criteri desiderati. Quindi usa Collections.sort() sul tuo ArrayList.

Se in un secondo momento si desidera ordinare in base a criteri diversi, chiamare di nuovo Collections.sort() con un altro Comparator.

+0

Potete fornire un esempio di come potrebbe apparire il mio metodo comparativo()? –

+0

@Sheehan La documentazione spiega il contratto. Spetta a te determinare l'ordine. Pensalo come se cercassi un libro in biblioteca, ad es. per prima cosa vai nella sezione "Fiction" o "Non-Fiction", poi cerchi l'intero numero, quindi la parte dopo il decimale ... ad es. confronti prima le cose "più significative" e continui a restringere.Se una parte più significativa è più di un'altra, allora questo termina l'ordine (come hai già trovato l'ordine migliore). –

+0

Questa risposta non funziona per me, ho due colonne, in primo luogo vorrei ordinare un arraylist basato sulle colonne uno dopo che vorrei ordinare sulle colonne due, ma non funziona correttamente e il mio arraylist è ordinato su colonne due in totale! –

2

Vedi Collections.sort con un comparatore esplicita (o la Collections.sort tipo che richiede l'input di implementare Comparable, se si preferisce).

28

Se (quasi) si desidera utilizzare sempre tale ordine, è possibile aggiungere l'interfaccia Comparable a Quote e implementare un metodo di confronto.

public int compareTo(Quote quote) { 
    int result = this.getName().compareTo(quote.getName()); 
    if (result == 0) { 
     result = this.getChange().compareTo(quote.getChange()); 
    } 
    if (result == 0) { 
     result = this.getPercentChange().compareTo(quote.getPercentChange()); 
    } 
    return result; 
} 

Quindi utilizzare una raccolta ordinata o ordinare un elenco e le virgolette verranno ordinate.

Per l'ordinamento ad hoc, un comparatore separato, possibilmente anonimo, è migliore.

+1

per "Per l'ordinamento ad hoc, un comparatore separato, possibilmente anonimo, è migliore." +1 – user3437460

14

Tutti hanno ragione a voler utilizzare i Comparatori. Estendendosi su questa idea, se si vuole essere in grado di ordinare su più criteri, quindi una classe come questo lavoro per voi:

public class MultiComparator<T> implements Comparator<T> { 
    private List<Comparator<T>> comparators; 

    public MultiComparator(List<Comparator<T>> comparators) { 
     this.comparators = comparators; 
    } 

    public int compare(T o1, T o2) { 
     for (Comparator<T> comparator : comparators) { 
      int comparison = comparator.compare(o1, o2); 
      if (comparison != 0) return comparison; 
     } 
     return 0; 
    } 
} 

Poi basta scrivere comparatori molto semplici per qualsiasi campi si desidera e si possono combinare loro in comparatori più complessi più facilmente e con più riutilizzo.

+0

Se ci sono molti confronti e la prestazione è un problema, l'Elenco privato > potrebbe essere memorizzato come un comparatore di array [] (viene impostato una volta al costruttore, mai modificato e mai letto dai clienti) - per lo meno renderlo definitivo. –

+0

D'accordo, o forse la lezione potrebbe essere definitiva. Ho praticamente scritto questo a freddo per dimostrare l'idea. Ci sarebbe davvero qualcosa del genere nel JDK, e sarei sorpreso se non fosse in un numero qualsiasi di librerie di collezioni ... – romacafe

+0

Quale sarebbe la complessità di questo tipo di concatenamento di comparatori? Stiamo essenzialmente ordinando ogni volta che incateniamo i comparatori? Quindi facciamo un'operazione n * log (n) per ogni comparatore? –

11

Dai un'occhiata alla ComparatorChain della Apache Commons Collection. Questo dovrebbe fare il lavoro. Non implementare la logica se è già disponibile e testata.
Nel seguente sito ho un tutorial: Sorting Objects By Multiple Attributes"

+0

+1 Grazie per questo, dover ricorrere a una libreria di terze parti per questo è IMHO un'enorme lacuna del linguaggio di programmazione Java.Io sono d'accordo con gli straniopici, non implementare la propria implementazione quando è una libreria in grado di farlo. Link diretto alla classe ComparatorChain libera da dipendenza: http://www.jarvana.com/jarvana/view/commons-collections/commons-collections/3.2.1/commons-collections-3.2.1 -sources.jar! /org/apache/commons/collections/comparators/ComparatorChain.java – Moritz

+0

Grazie per il largo codice di esempio per dimostrare il concetto. Questo (combinato con il tuo articolo) è un'ottima risposta alla domanda OP. –

Problemi correlati