2010-02-22 5 views
27

Angenommen, ich habe eine Liste (oder Set):Filter- und Sortierliste google Sammlungen mit

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

Ich mag einen ImmutableList (Set) zurück zu bekommen, dass Sorten/Gruppen Begriffe in natürlicher Reihenfolge, wo Begriffe, die beginnen mit "src" sind zuerst, "assoc" zweite und "dest" zuletzt. Wenn ein Begriff diese nicht enthält, sollte er aus der resultierenden Liste entfernt werden.

Daher ist das Ergebnis hier "srcB", "srcT", "assocX", "destA".

Ich denke, dass ich dies mit einer Kombination von Iterables.Filter oder Predicates tun kann, aber einfach nicht sehen. Es muss eine prägnante Vorgehensweise geben, denke ich.

EDIT: Ein Satz anstelle einer Liste funktioniert auch.

Antwort

32

Solange diese drei Präfixe die einzigen Dinge, die Sie interessieren, ich so etwas wie dies würde vorschlagen:

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) 
      ) 
    ); 

Diese Lösung definitiv nicht unglaublich gut würde skalieren, wenn Sie mehr Präfixe beginnen Hinzufügen zu herausfiltern oder sortieren, da Sie sowohl den Filter als auch das Gewicht jedes Präfixes fortlaufend aktualisieren müssen.

+11

In den anderen Fällen ist es besser, 'IllegalArgumentException() 'als' return 3' zu werfen. –

0

Ich denke, Sie müssen zuerst das Prädikat verwenden, um Elemente zu beseitigen, die Sie nicht wollen, und implementieren Sie eine Comparator und sortieren Sie Ihre Liste.

12

Werfen Sie einen Blick auf 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(); 

Obwohl dies zugegebenermaßen ein Set zurückgibt.

0

Normalerweise ist es ein schlechtes Design, um eindeutig unterschiedliche Daten wie diese zu sammeln. In Ihrem Fall, wenn Sie "assocX" sagen, hat "assoc" eine separate Bedeutung von "X", aber Sie verschmelzen sie zusammen.

Also würde ich vorschlagen, eine Klasse mit zwei Feldern zu entwerfen. Dann können Sie eine Reihenfolge für das erste Feld erstellen, eine weitere für die zweite, und kombinieren Sie sie (z. B. Bestell-Nr. Verbindung()). Mit einer toString() -Methode, die tut diese Felder in eine Zeichenfolge zusammenführen. Als Bonus kann dies die Speichernutzung durch Teilen erheblich reduzieren.

Also würden Sie eine Liste solcher Objekte sortieren, und wenn Sie sie drucken wollten, würden Sie einfach toString() auf ihnen aufrufen.