Quelle est la meilleure façon de filtrer une Collection Java?

je veux filtrer un java.util.Collection , basé sur le prédicat.

571
demandé sur user2864740 2008-09-23 20:26:26

26 réponses

Java 8 ( 2014 ) résout ce problème en utilisant streams et lambdas dans une ligne de code:

List<Person> beerDrinkers = persons.stream()
    .filter(p -> p.getAge() > 16).collect(Collectors.toList());

voici un tutorial .

utiliser Collection#removeIf pour modifier la collecte en place. (Avis: Dans ce cas, le prédicat sera de supprimer des objets qui satisfont le prédicat):

persons.removeIf(p -> p.getAge() <= 16);

lambdaj permet de filtrer les collections sans écrire de boucles ou de classes intérieures:

List<Person> beerDrinkers = select(persons, having(on(Person.class).getAge(),
    greaterThan(16)));

Pouvez-vous imaginer quelque chose de plus lisible?

Avertissement: je suis un contributeur sur lambdaj

554
répondu Mario Fusco 2017-11-20 19:23:48

en supposant que vous utilisez Java 1.5 , et que vous ne pouvez pas ajouter Google Collections , je ferais quelque chose de très similaire à ce que les gars de Google ont fait. C'est une légère variation sur Jon commentaires.

ajoutez D'abord cette interface à votre base de données.

public interface IPredicate<T> { boolean apply(T type); }

Ses exécutants peuvent répondre à un certain prédicat est vrai d'un certain type. Par exemple: Si T étaient User et AuthorizedUserPredicate<User> met en œuvre IPredicate<T> , puis AuthorizedUserPredicate#apply retourne si le passé dans User est autorisé.

alors dans une classe utilitaire, on pourrait dire

public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
    Collection<T> result = new ArrayList<T>();
    for (T element: target) {
        if (predicate.apply(element)) {
            result.add(element);
        }
    }
    return result;
}

donc, en supposant que vous avez l'utilisation de ce qui précède pourrait être

Predicate<User> isAuthorized = new Predicate<User>() {
    public boolean apply(User user) {
        // binds a boolean method in User to a reference
        return user.isAuthorized();
    }
};
// allUsers is a Collection<User>
Collection<User> authorizedUsers = filter(allUsers, isAuthorized);

si la performance sur la vérification linéaire est une préoccupation, alors je pourrais vouloir avoir un objet de domaine qui a la collection cible. L'objet de domaine qui a le la collection cible aurait une logique de filtrage pour les méthodes qui initialisent, ajoutent et fixent la collection cible.

mise à jour:

dans la classe utility (disons Predicate), j'ai ajouté une méthode select avec une option pour la valeur par défaut lorsque le predicate ne renvoie pas la valeur attendue, et aussi une propriété statique pour les paramètres à utiliser à l'intérieur du Nouveau IPredicate.

public class Predicate {
    public static Object predicateParams;

    public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
        Collection<T> result = new ArrayList<T>();
        for (T element : target) {
            if (predicate.apply(element)) {
                result.add(element);
            }
        }
        return result;
    }

    public static <T> T select(Collection<T> target, IPredicate<T> predicate) {
        T result = null;
        for (T element : target) {
            if (!predicate.apply(element))
                continue;
            result = element;
            break;
        }
        return result;
    }

    public static <T> T select(Collection<T> target, IPredicate<T> predicate, T defaultValue) {
        T result = defaultValue;
        for (T element : target) {
            if (!predicate.apply(element))
                continue;
            result = element;
            break;
        }
        return result;
    }
}

l'exemple suivant cherche objets manquants entre collections:

List<MyTypeA> missingObjects = (List<MyTypeA>) Predicate.filter(myCollectionOfA,
    new IPredicate<MyTypeA>() {
        public boolean apply(MyTypeA objectOfA) {
            Predicate.predicateParams = objectOfA.getName();
            return Predicate.select(myCollectionB, new IPredicate<MyTypeB>() {
                public boolean apply(MyTypeB objectOfB) {
                    return objectOfB.getName().equals(Predicate.predicateParams.toString());
                }
            }) == null;
        }
    });

l'exemple suivant, recherche une instance dans une collection, et renvoie le premier élément de la collection comme valeur par défaut lorsque l'instance n'est pas trouvée:

MyType myObject = Predicate.select(collectionOfMyType, new IPredicate<MyType>() {
public boolean apply(MyType objectOfMyType) {
    return objectOfMyType.isDefault();
}}, collectionOfMyType.get(0));

UPDATE (after Java 8 release):

Cela fait plusieurs années que J'ai (Alan) posté cette réponse pour la première fois, et je ne peux toujours pas croire que je recueille ainsi des points pour cette réponse. En tout cas, maintenant que Java 8 a introduit des fermetures à la langue, ma réponse serait maintenant considérablement différente, et plus simple. Avec Java 8, Il n'y a pas besoin d'une classe d'utilité statique distincte. Donc, si vous voulez trouver le 1er élément qui correspond à votre prédicat.

final UserService userService = ... // perhaps injected IoC
final Optional<UserModel> userOption = userCollection.stream().filter(u -> {
    boolean isAuthorized = userService.isAuthorized(u);
    return isAuthorized;
}).findFirst();

L'API JDK 8 pour optionals a la capacité de get() , isPresent() , orElse(defaultUser) , orElseGet(userSupplier) et orElseThrow(exceptionSupplier) , ainsi que d'autres fonctions "monades" telles que map , flatMap et filter .

si vous voulez simplement collecter tous les utilisateurs qui correspondent au prédicat, puis utiliser le Collectors pour terminer le flux dans la collecte souhaitée.

final UserService userService = ... // perhaps injected IoC
final List<UserModel> userOption = userCollection.stream().filter(u -> {
    boolean isAuthorized = userService.isAuthorized(u);
    return isAuthorized;
}).collect(Collectors.toList());

Voir ici pour plus d'exemples sur la façon dont Java 8 flux de travail.

215
répondu Alan 2016-06-11 16:09:52
87
répondu Kevin Wong 2015-11-17 06:11:33

"Meilleure" façon est d'une trop grande demande. Est-il "le plus court"? "Le plus rapide"? "Lisible"? Filtrer en place ou dans une autre collection?

la façon la plus simple (mais pas la plus lisible) est de l'itérer et D'utiliser Iterator.supprimer () méthode:

Iterator<Foo> it = col.iterator();
while( it.hasNext() ) {
  Foo foo = it.next();
  if( !condition(foo) ) it.remove();
}

Maintenant, pour la rendre plus lisible, vous pouvez l'envelopper dans une méthode utilitaire. Puis inventer une interface IPredicate, créer une implémentation anonyme de cette interface et faire quelque chose comme:

CollectionUtils.filterInPlace(col,
  new IPredicate<Foo>(){
    public boolean keepIt(Foo foo) {
      return foo.isBar();
    }
  });

où filterInPlace () itérate The collection and calls Predicate.keepIt() pour savoir si l'instance pour être conservés dans la collection.

Je ne vois pas vraiment de justification pour faire venir une bibliothèque tierce juste pour cette tâche.

60
répondu Vladimir Dyuzhev 2014-07-17 16:26:29

prendre en considération Google Collections pour une mise à jour des Collections de cadre qui prend en charge les génériques.

UPDATE : la bibliothèque des collections google est maintenant dépréciée. Vous devez utiliser la dernière version de Guava à la place. Il a encore Toutes les mêmes extensions au cadre de collections, y compris un mécanisme de filtrage basé sur un prédicat.

60
répondu Heath Borders 2015-07-13 19:26:35

Attendre pour Java 8:

List<Person> olderThan30 = 
  //Create a Stream from the personList
  personList.stream().
  //filter the element to select only those with age >= 30
  filter(p -> p.age >= 30).
  //put those filtered elements into a new List.
  collect(Collectors.toList());
23
répondu gavenkoa 2015-03-24 08:24:01

depuis la sortie anticipée de Java 8, Vous pouvez essayer quelque chose comme:

Collection<T> collection = ...;
Stream<T> stream = collection.stream().filter(...);

par exemple, si vous aviez une liste d'entiers et que vous vouliez filtrer les nombres qui sont > 10 et ensuite imprimer ces nombres sur la console, vous pourriez faire quelque chose comme:

List<Integer> numbers = Arrays.asList(12, 74, 5, 8, 16);
numbers.stream().filter(n -> n > 10).forEach(System.out::println);
10
répondu Josh M 2013-10-27 21:41:55

je vais jeter RxJava dans l'anneau, qui est également disponible sur Android . RxJava n'est peut-être pas toujours la meilleure option, mais elle vous donnera plus de flexibilité si vous souhaitez ajouter plus de transformations sur votre collection ou gérer les erreurs tout en filtrant.

Observable.from(Arrays.asList(1, 2, 3, 4, 5))
    .filter(new Func1<Integer, Boolean>() {
        public Boolean call(Integer i) {
            return i % 2 != 0;
        }
    })
    .subscribe(new Action1<Integer>() {
        public void call(Integer i) {
            System.out.println(i);
        }
    });

sortie:

1
3
5

plus de détails sur filter de RxJava peuvent être trouvés ici .

9
répondu anon 2016-02-14 23:25:12

Le programme d'installation:

public interface Predicate<T> {
  public boolean filter(T t);
}

void filterCollection(Collection<T> col, Predicate<T> predicate) {
  for (Iterator i = col.iterator(); i.hasNext();) {
    T obj = i.next();
    if (predicate.filter(obj)) {
      i.remove();
    }
  }
}

L'utilisation:

List<MyObject> myList = ...;
filterCollection(myList, new Predicate<MyObject>() {
  public boolean filter(MyObject obj) {
    return obj.shouldFilter();
  }
});
6
répondu jon 2008-09-23 16:41:27

Que Diriez-vous D'un Java simple et direct

 List<Customer> list ...;
 List<Customer> newList = new ArrayList<>();
 for (Customer c : list){
    if (c.getName().equals("dd")) newList.add(c);
 }

Simple, lisible et facile (et fonctionne sous Android!) Mais si vous utilisez Java 8 Vous pouvez le faire dans une ligne douce:

List<Customer> newList = list.stream().filter(c -> c.getName().equals("dd")).collect(toList());

Notez que toList() est statiquement importés

6
répondu Nestor Hernandez Loli 2014-05-12 05:03:57

êtes-vous sûr de vouloir filtrer la Collection elle-même, plutôt qu'un itérateur?

voir org.Apache.commun.collection.les itérateurs.Filtrateur

ou à l'aide de la version 4 de apache commons org.Apache.commun.collections4.les itérateurs.Filtrateur

6
répondu ykaganovich 2014-07-16 08:43:33

voyons comment filtrer une liste JDK intégrée et une MutableList en utilisant Eclipse Collections (anciennement GS Collections ).

List<Integer> jdkList = Arrays.asList(1, 2, 3, 4, 5);
MutableList<Integer> ecList = Lists.mutable.with(1, 2, 3, 4, 5);

si vous vouliez filtrer les nombres inférieurs à 3, vous vous attendriez aux sorties suivantes.

List<Integer> selected = Lists.mutable.with(1, 2);
List<Integer> rejected = Lists.mutable.with(3, 4, 5);

Voici comment vous pouvez filtrer en utilisant une classe interne anonyme comme le Predicate .

Predicate<Integer> lessThan3 = new Predicate<Integer>()
{
    public boolean accept(Integer each)
    {
        return each < 3;
    }
};

Assert.assertEquals(selected, Iterate.select(jdkList, lessThan3));

Assert.assertEquals(selected, ecList.select(lessThan3));

voici quelques alternatives au filtrage des listes JDK et Eclipse Collections MutableLists using the Predicates factory.

Assert.assertEquals(selected, Iterate.select(jdkList, Predicates.lessThan(3)));

Assert.assertEquals(selected, ecList.select(Predicates.lessThan(3)));

Voici une version qui n'affecte pas un objet pour le prédicat, en utilisant les prédicats" 1519340920 usine à la place avec la méthode selectWith qui prend un Predicate2 .

Assert.assertEquals(
    selected, ecList.selectWith(Predicates2.<Integer>lessThan(), 3));

parfois vous souhaitez filtrer sur une condition négative. Il existe une méthode spéciale dans les collections Eclipse pour celle appelée reject .

Assert.assertEquals(rejected, Iterate.reject(jdkList, lessThan3));

Assert.assertEquals(rejected, ecList.reject(lessThan3));

Voici comment vous pouvez filtrer en utilisant un Java 8 lambda comme le Predicate .

Assert.assertEquals(selected, Iterate.select(jdkList, each -> each < 3));
Assert.assertEquals(rejected, Iterate.reject(jdkList, each -> each < 3));

Assert.assertEquals(selected, gscList.select(each -> each < 3));
Assert.assertEquals(rejected, gscList.reject(each -> each < 3));

La méthode partition sera de retour en deux collections, contenant les éléments sélectionnés par et rejeté par le Predicate .

PartitionIterable<Integer> jdkPartitioned = Iterate.partition(jdkList, lessThan3);
Assert.assertEquals(selected, jdkPartitioned.getSelected());
Assert.assertEquals(rejected, jdkPartitioned.getRejected());

PartitionList<Integer> ecPartitioned = gscList.partition(lessThan3);
Assert.assertEquals(selected, ecPartitioned.getSelected());
Assert.assertEquals(rejected, ecPartitioned.getRejected());

Note: je suis un committer pour Eclipse Collection.

5
répondu Donald Raab 2016-02-08 04:20:22

avec le foreach DSL vous pouvez écrire

import static ch.akuhn.util.query.Query.select;
import static ch.akuhn.util.query.Query.$result;
import ch.akuhn.util.query.Select;

Collection<String> collection = ...

for (Select<String> each : select(collection)) {
    each.yield = each.value.length() > 3;
}

Collection<String> result = $result();

étant donné une collection de [The, quick, brown, fox, jumps, over, the, lazy, dog], il en résulte en [quick, brown, jumps, over, lazy], c'est-à-dire toutes les cordes de plus de trois caractères.

tous les styles d'itération supportés par la DSL ForEach sont

  • AllSatisfy
  • AnySatisfy
  • Collect
  • Counnt
  • CutPieces
  • Detect
  • GroupedBy
  • IndexOf
  • InjectInto
  • Reject
  • Select

pour plus de détails, veuillez vous référer à https://www.iam.unibe.ch/scg/svn_repos/Sources/ForEach

4
répondu akuhn 2008-12-03 16:20:21

Le Collections2.filtre(Collecte,Prédicat) méthode Google Goyave bibliothèque qui fait exactement ce que vous cherchez.

4
répondu Kevin Wong 2012-08-09 21:19:44

ceci, combiné avec l'absence de véritables Fermetures, est ma plus grande plainte pour Java. Honnêtement, la plupart des méthodes mentionnées ci-dessus sont assez faciles à lire et vraiment efficaces; cependant, après avoir passé du temps avec .Net, Erlang, etc... liste de compréhension intégrée au niveau du langage rend tout tellement plus propre. Sans ajout au niveau de la langue, Java ne peut pas être aussi propre que beaucoup d'autres langues dans ce domaine.

si la performance est un énorme problème, Google collections est la voie à suivre (ou écrire votre propre utilité prédicate simple). Lambdaj syntaxe est plus lisible pour certaines personnes, mais il n'est pas tout à fait aussi efficace.

et puis il y a une bibliothèque que j'ai écrite. J'ignorerai toute question relative à son efficacité (Oui, c'est ce qu'il y a de mauvais)...... Oui, je sais qu'il est clairement basé sur la réflexion, et Non Je ne l'utilise pas réellement, mais il fonctionne:

LinkedList<Person> list = ......
LinkedList<Person> filtered = 
           Query.from(list).where(Condition.ensure("age", Op.GTE, 21));

OU

LinkedList<Person> list = ....
LinkedList<Person> filtered = Query.from(list).where("x => x.age >= 21");
3
répondu jdc0589 2011-06-23 03:55:48

JFilter http://code.google.com/p/jfilter / est le mieux adapté à vos besoins.

JFilter est une bibliothèque open source simple et de haute performance pour interroger la collection de grains de Java.

caractéristiques principales

  • Support de collection (java.util.Collection, java.util.Carte et Tableau) propriétés.
  • Support de la collection à l'intérieur de la collection de n'importe quelle profondeur.
  • prise en charge des requêtes internes.
  • prise en charge des requêtes paramétrées.
  • peut filtrer 1 million d'enregistrements en quelques 100 ms.
  • filtre (requête) est donné dans le format JSON simple, il est comme les requêtes Mangodb. En voici quelques exemples.
  • { "id":{"$chier":"10"}
    • lorsque la propriété ID de l'article est inférieure à 10.
  • {"id": {"$": ["0", "100"]}}
    • lorsque la propriété ID de l'objet est 0 ou 100.
  • {"comptes":{"lineAmount":"1"}}
    • où le montant de la ligne est égal à 1.
  • { "$": [{"id": "0"}, {"billingAddress":{"ville":"DEL"}}]}
    • où la propriété id est 0 et adresse de facturation.la propriété de la ville est DEL.
  • {"comptes":{"taxes":{ "key":{"code":"TPS"}, "value":{"$gt": "1.01"}}}}
    • où lineItems collection biens de type paramétrisé ayant des taxes type de carte biens de type paramétrisé ayant un code égal à la valeur aux fins de la TPS supérieur à 1,01.
  • {'$': [{'code':'10'},{'sku": {'$et':[{'prix':{'$dans':['20', '40']}}, {'code':'RedApple'}]}}]}
    • Sélectionnez tous les produits pour lesquels le code produit est 10 ou le prix sku en 20 et 40 et le code sku est "RedApple".
2
répondu Kamran Ali Khan 2012-04-05 10:46:58

j'ai écrit une longue Itérable classe qui soutiennent l'application algorithmes fonctionnels sans avoir à copier le contenu de la collection.

Utilisation:

List<Integer> myList = new ArrayList<Integer>(){ 1, 2, 3, 4, 5 }

Iterable<Integer> filtered = Iterable.wrap(myList).select(new Predicate1<Integer>()
{
    public Boolean call(Integer n) throws FunctionalException
    {
        return n % 2 == 0;
    }
})

for( int n : filtered )
{
    System.out.println(n);
}

le code ci-dessus va effectivement exécuter

for( int n : myList )
{
    if( n % 2 == 0 ) 
    {
        System.out.println(n);
    }
}
2
répondu Vincent Robert 2014-07-23 15:50:02

Utiliser "151910920 De La Collection" Moteur De Requête (CQEngine) . C'est de loin le moyen le plus rapide pour ce faire.

Voir aussi: comment interrogez-vous les collections d'objets en Java (Type critères/SQL)?

2
répondu npgall 2017-05-23 12:18:25

depuis java 9 Collectors.filtering est activé:

public static <T, A, R>
    Collector<T, ?, R> filtering(Predicate<? super T> predicate,
                                 Collector<? super T, A, R> downstream)

par conséquent, le filtrage devrait être:

collection.stream().collect(Collectors.filtering(predicate, collector))

exemple:

List<Integer> oddNumbers = List.of(1, 19, 15, 10, -10).stream()
            .collect(Collectors.filtering(i -> i % 2 == 1, Collectors.toList()));
2
répondu fbokovikov 2018-05-24 13:59:00

La simple pré-Java8 solution:

ArrayList<Item> filtered = new ArrayList<Item>(); 
for (Item item : items) if (condition(item)) filtered.add(item);

malheureusement, cette solution n'est pas entièrement Générique, sortant une liste plutôt que le type de la collection donnée. Aussi, faire venir des bibliothèques ou des fonctions d'écriture qui enveloppent ce code me semble être exagéré à moins que la condition soit complexe, mais alors vous pouvez écrire une fonction pour la condition.

1
répondu Andrew McKnight 2014-07-03 19:15:32

https://code.google.com/p/joquery/

supporte différentes possibilités,

collection donnée,

Collection<Dto> testList = new ArrayList<>();

de type,

class Dto
{
    private int id;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getText()
    {
        return text;
    }
}

filtre

Java 7

Filter<Dto> query = CQ.<Dto>filter(testList)
    .where()
    .property("id").eq().value(1);
Collection<Dto> filtered = query.list();

Java 8

Filter<Dto> query = CQ.<Dto>filter(testList)
    .where()
    .property(Dto::getId)
    .eq().value(1);
Collection<Dto> filtered = query.list();

aussi,

Filter<Dto> query = CQ.<Dto>filter()
        .from(testList)
        .where()
        .property(Dto::getId).between().value(1).value(2)
        .and()
        .property(Dto::grtText).in().value(new string[]{"a","b"});

Tri (également disponible pour le Java 7)

Filter<Dto> query = CQ.<Dto>filter(testList)
        .orderBy()
        .property(Dto::getId)
        .property(Dto::getName)
    Collection<Dto> sorted = query.list();

Grouping (également disponible pour le Java 7)

GroupQuery<Integer,Dto> query = CQ.<Dto,Dto>query(testList)
        .group()
        .groupBy(Dto::getId)
    Collection<Grouping<Integer,Dto>> grouped = query.list();

Joins (également disponible pour le Java 7)

Donnée,

class LeftDto
{
    private int id;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getText()
    {
        return text;
    }
}

class RightDto
{
    private int id;
    private int leftId;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getLeftId()
        {
            return leftId;
        }

    public int getText()
    {
        return text;
    }
}

class JoinedDto
{
    private int leftId;
    private int rightId;
    private String text;

    public JoinedDto(int leftId,int rightId,String text)
    {
        this.leftId = leftId;
        this.rightId = rightId;
        this.text = text;
    }

    public int getLeftId()
    {
        return leftId;
    }

    public int getRightId()
        {
            return rightId;
        }

    public int getText()
    {
        return text;
    }
}

Collection<LeftDto> leftList = new ArrayList<>();

Collection<RightDto> rightList = new ArrayList<>();

Can

Collection<JoinedDto> results = CQ.<LeftDto, LeftDto>query().from(leftList)
                .<RightDto, JoinedDto>innerJoin(CQ.<RightDto, RightDto>query().from(rightList))
                .on(LeftFyo::getId, RightDto::getLeftId)
                .transformDirect(selection ->  new JoinedDto(selection.getLeft().getText()
                                                     , selection.getLeft().getId()
                                                     , selection.getRight().getId())
                                 )
                .list();

Expressions

Filter<Dto> query = CQ.<Dto>filter()
    .from(testList)
    .where()
    .exec(s -> s.getId() + 1).eq().value(2);
1
répondu Low Flying Pelican 2014-09-03 12:59:35

ma réponse s'appuie sur celle de Kevin Wong, ici comme une doublure utilisant l'expression CollectionUtils de spring et une Java 8 lambda .

CollectionUtils.filter(list, p -> ((Person) p).getAge() > 16);

c'est aussi concis et lisible que n'importe quelle alternative que j'ai vu (sans utiliser des bibliothèques basées sur l'aspect)

Printemps CollectionUtils est disponible à partir du printemps de la version 4.0.2.Relâchez, et rappelez-vous que vous avez besoin de JDK 1.8 et niveau de langue 8+.

1
répondu vikingsteve 2015-04-22 11:18:24

quelques très grandes grandes réponses ici. Moi, je voudrais garder les thins aussi simple et lisible que possible:

public abstract class AbstractFilter<T> {

    /**
     * Method that returns whether an item is to be included or not.
     * @param item an item from the given collection.
     * @return true if this item is to be included in the collection, false in case it has to be removed.
     */
    protected abstract boolean excludeItem(T item);

    public void filter(Collection<T> collection) {
        if (CollectionUtils.isNotEmpty(collection)) {
            Iterator<T> iterator = collection.iterator();
            while (iterator.hasNext()) {
                if (excludeItem(iterator.next())) {
                    iterator.remove();
                }
            }
        }
    }
}
1
répondu Lawrence 2018-04-05 16:22:48

en utilisant java 8 , spécifiquement lambda expression , vous pouvez le faire simplement comme dans l'exemple suivant:

myProducts.stream().filter(prod -> prod.price>10).collect(Collectors.toList())

où, pour chaque product à l'intérieur de myProducts collection , si prod.price>10 , ajouter ce produit à la nouvelle liste filtrée.

0
répondu hd84335 2015-12-12 21:47:55

Avec Goyave:

Collection<Integer> collection = Lists.newArrayList(1, 2, 3, 4, 5);

Iterators.removeIf(collection.iterator(), new Predicate<Integer>() {
    @Override
    public boolean apply(Integer i) {
        return i % 2 == 0;
    }
});

System.out.println(collection); // Prints 1, 3, 5
0
répondu ZhekaKozlov 2016-12-15 09:26:44

j'ai dû filtrer une liste en fonction des valeurs déjà présentes dans la liste. Par exemple, supprimez toutes les valeurs suivantes qui sont inférieures à la valeur courante. {2 5 3 4 7 5} -> {2 5 7}. Ou par exemple, pour supprimer tous les doublons {3 5 4 2 3 5 6} -> {3 5 4 2 6}.

public class Filter {
    public static <T> void List(List<T> list, Chooser<T> chooser) {
        List<Integer> toBeRemoved = new ArrayList<>();
        leftloop:
        for (int right = 1; right < list.size(); ++right) {
            for (int left = 0; left < right; ++left) {
                if (toBeRemoved.contains(left)) {
                    continue;
                }
                Keep keep = chooser.choose(list.get(left), list.get(right));
                switch (keep) {
                    case LEFT:
                        toBeRemoved.add(right);
                        continue leftloop;
                    case RIGHT:
                        toBeRemoved.add(left);
                        break;
                    case NONE:
                        toBeRemoved.add(left);
                        toBeRemoved.add(right);
                        continue leftloop;
                }
            }
        }

        Collections.sort(toBeRemoved, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });

        for (int i : toBeRemoved) {
            if (i >= 0 && i < list.size()) {
                list.remove(i);
            }
        }
    }

    public static <T> void List(List<T> list, Keeper<T> keeper) {
        Iterator<T> iterator = list.iterator();
        while (iterator.hasNext()) {
            if (!keeper.keep(iterator.next())) {
                iterator.remove();
            }
        }
    }

    public interface Keeper<E> {
        boolean keep(E obj);
    }

    public interface Chooser<E> {
        Keep choose(E left, E right);
    }

    public enum Keep {
        LEFT, RIGHT, BOTH, NONE;
    }
}

ce sera utilisé comme ceci.

List<String> names = new ArrayList<>();
names.add("Anders");
names.add("Stefan");
names.add("Anders");
Filter.List(names, new Filter.Chooser<String>() {
    @Override
    public Filter.Keep choose(String left, String right) {
        return left.equals(right) ? Filter.Keep.LEFT : Filter.Keep.BOTH;
    }
});
0
répondu Fredrik Metcalf 2017-06-15 14:28:05