2010-02-22 9 views
27

Supposons que j'ai une liste (ou Set):filtre et trier la liste en utilisant les collections google

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

Je voudrais revenir un ImmutableList (Set) que les termes de sortes/groupes dans l'ordre naturel où les termes qui commencent avec "src" en premier, "assoc" en second et "dest" en dernier. Si un terme ne les contient pas, il doit être supprimé de la liste résultante.

Par conséquent, le résultat ici est "srcB", "srcT", "assocX", "destA".

Je pense que je peux le faire avec une combinaison de Iterables.filter ou Predicates mais juste ne pas le voir. Il doit y avoir une façon succincte de le faire, je pense.

EDIT: Un ensemble à la place d'une liste fonctionne également.

Répondre

32

Tant que ces trois préfixes sont les seules choses que vous aimez, je vous suggère quelque chose comme ceci:

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

Cette solution ne serait pas scalable définitivement incroyablement bien si vous commencez à ajouter plusieurs préfixes à filtrer ou trier par, puisque vous devez continuellement mettre à jour à la fois le filtre et le poids de chaque préfixe.

+11

Dans les autres cas, il vaut mieux lancer 'nouveau IllegalArgumentException()' que 'return 3'. –

0

Je pense que vous devrez d'abord utiliser le prédicat pour éliminer les éléments que vous ne voulez pas, et mettre en œuvre un Comparator et trier votre liste.

12

Jetez un oeil à 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(); 

Bien que cela, certes, renvoie un ensemble.

0

Habituellement, il est de mauvaise conception de rassembler des données clairement distinctes comme celle-ci. Dans votre cas, quand vous dites "assocX", "assoc" a une signification distincte de "X", mais vous les fusionnez ensemble.

Donc, je suggère de concevoir une classe avec deux champs. Vous pouvez ensuite créer un ordre sur le premier champ, un autre sur le second et les combiner (par exemple, Ordering # compound()). Avec une méthode toString() fusionne ces champs en une chaîne. En prime, cela peut réduire considérablement l'utilisation de la mémoire via le partage.

Ainsi vous triez une liste de tels objets, et si vous vouliez les imprimer, vous appelez simplement toString() sur eux.

Questions connexes