2010-02-22 5 views
27

Supponiamo che ho una lista (o Set):filtro e ordinare elenco utilizzando collezioni google

List<String> testList = Lists.newArrayList("assocX","srcT","destA","srcX", "don't care Y", "garbage", "srcB"); 

Vorrei tornare un ImmutableList (Set) che ordina/gruppi di termini in ordine naturale in cui i termini che iniziano con "src" sono i primi, "assoc" e "dest" ultimi. Se un termine non contiene quelli allora dovrebbe essere rimosso dalla lista risultante.

Pertanto il risultato qui è "srcB", "srcT", "assocX", "Desta".

credo di poter fare questo con una certa combinazione di Iterables.filter o predicati, ma semplicemente non vederlo. Ci deve essere un modo succinto di farlo penso.

EDIT: Un set al posto di una lista funziona pure.

risposta

32

Finché queste tre prefissi sono le uniche cose che ti interessano, io suggerirei qualcosa di simile:

Predicate<String> filter = new Predicate<String>() { 
     @Override 
     public boolean apply(String input) { 
      return input.startsWith("src") || input.startsWith("assoc") || input.startsWith("dest"); 
     } 
    }; 

    Function<String, Integer> assignWeights = new Function<String, Integer>() { 
     @Override 
     public Integer apply(String from) { 
      if (from.startsWith("src")) { 
       return 0; 
      } else if (from.startsWith("assoc")) { 
       return 1; 
      } else if (from.startsWith("dest")) { 
       return 2; 
      } else { 
       /* Shouldn't be possible but have to do something */ 
       throw new IllegalArgrumentException(from + " is not a valid argument"); 
      } 
     } 
    }; 

    ImmutableList<String> sortedFiltered = ImmutableList.copyOf(
      Ordering.natural().onResultOf(assignWeights).sortedCopy(
        Iterables.filter(testList, filter) 
      ) 
    ); 

Questa soluzione sicuramente sarebbe non scalabilità orizzontale incredibilmente bene se si avvia l'aggiunta di ulteriori prefissi a filtrare o ordinare in base al fatto che è necessario aggiornare continuamente sia il filtro che il peso di ciascun prefisso.

+11

Negli altri casi è meglio "gettare nuovo IllegalArgumentException()" di "return 3". –

0

Penso che prima dovrai utilizzare il predicato per eliminare elementi che non vuoi e l'attrezzo uno Comparator e ordinare il tuo elenco.

12

Dai un'occhiata alla This Google Collections example.

Function<Fruit, String> getNameFunction = new Function<Fruit, String>() { 
    public String apply(Fruit from) { 
     return from.getName(); 
    } 
}; 

Ordering<Fruit> nameOrdering = Ordering.natural().onResultOf(getNameFunction); 

ImmutableSortedSet<Fruit> sortedFruits = ImmutableSortedSet.orderedBy(
    nameOrdering).addAll(fruits).build(); 

Anche se questo, certamente, restituisce un Set.

0

solito è cattivo design per raccogliere dati nettamente distinte come questo. Nel tuo caso, quando dici "assocX", "assoc" ha un significato separato da "X", eppure li unisci.

Quindi, vorrei suggerire la progettazione di una classe con due campi. Quindi puoi creare un ordinamento sul primo campo, un altro sul secondo e combinarli (ad esempio, numero d'ordine composto()). Con un metodo toString() che fa unisci questi campi in una stringa. Come bonus, questo può ridurre notevolmente l'utilizzo della memoria tramite la condivisione.

Quindi dovresti ordinare una lista di tali oggetti, e se volessi stamparli, chiameresti semplicemente suString().