web-dev-qa-db-fra.com

filtrer et trier la liste en utilisant Google Collections

Supposons que j'ai une liste (ou un ensemble):

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

Je voudrais récupérer un ensemble (ensemble) ImmutableList qui trie/regroupe les termes dans un ordre naturel, les termes commençant par "src" commençant par "assoc", puis "dest". Si un terme ne les contient pas, il devrait être supprimé de la liste des résultats.

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

Je pense que je peux le faire avec une combinaison d'Iterables.filter ou de Predicates mais en ne le voyant pas. Il doit y avoir une façon succincte de le faire je pense.

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

27
harschware

Tant que ces trois préfixes sont les seules choses qui vous intéressent, je suggérerais 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 certainement pas incroyablement évolutive si vous commenciez à ajouter plus de préfixes à filtrer ou à trier, car vous auriez à mettre à jour en permanence le filtre et le poids de chaque préfixe.

33
Paul Blessing

Regardez Cet exemple de Google Collections .

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 ceci, certes, retourne un Set.

12
extraneon

Généralement, c’est une mauvaise conception de rassembler des données clairement distinctes comme celle-ci. Dans votre cas, lorsque vous dites "assocX", "assoc" a une signification distincte de "X", mais vous les fusionnez ensemble.

Je suggérerais donc 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, Ordre # compound ()). Avec une méthode toString () que fait / fusionne ces champs dans une chaîne. En prime, cela peut réduire considérablement l'utilisation de la mémoire via le partage. 

Donc, vous seriez en train de trier une liste de tels objets, et si vous voulez les imprimer, vous devez simplement appeler toString ().

0
Dimitris Andreou