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


Je veux filtrer un java.util.Collection en fonction d'un prédicat.

Author: user2864740, 2008-09-23

26 answers

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

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

Voici un tutoriel.

Utiliser Collection#removeIf pour modifier la collection en place. (Remarque: Dans ce cas, le prédicat supprimera les 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 internes:

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
Author: 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. Ceci est une légère variation sur les commentaires de Jon.

Ajoutez d'abord cette interface à votre base de code.

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

Ses implémenteurs peuvent répondre lorsqu'un certain prédicat est vrai d'un certain type. Par exemple, si T était User et AuthorizedUserPredicate<User> implémente IPredicate<T>, alors AuthorizedUserPredicate#apply renvoie si le passé dans User est Authorized.

Alors dans une classe d'utilité, 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 les performances sur la vérification linéaire sont préoccupantes, alors je pourrais vouloir avoir un objet de domaine qui a la collection cible. L'objet de domaine qui a la collection cible aurait une logique de filtrage pour les méthodes qui initialisent, ajoutent et définissent la collection cible.

MISE À JOUR:

Dans la classe utilitaire (disons Prédicat), j'ai ajouté une méthode select avec une option pour la valeur par défaut lorsque le prédicat ne renvoie pas la valeur attendue, ainsi qu'une propriété statique pour les paramètres à utiliser dans le nouvel 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 recherche les objets manquants entre les 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));

MISE À JOUR (après la sortie de Java 8):

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 collecte des points SO pour cette réponse. En tout cas, maintenant que Java 8 a introduit des fermetures dans le langage, ma réponse serait maintenant considérablement différente et plus simple. Avec Java 8, il n'y a pas besoin d'une classe utilitaire 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 les options a le capacité à get(), isPresent(), orElse(defaultUser), orElseGet(userSupplier) et orElseThrow(exceptionSupplier), ainsi que d'autres "monadique" des fonctions telles que map, flatMap et filter.

Si vous souhaitez simplement collecter tous les utilisateurs qui correspondent au prédicat, utilisez le Collectors pour terminer le flux dans la collection 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 le fonctionnement des flux Java 8.

 215
Author: Alan, 2016-06-11 16:09:52

Utilisez CollectionUtils.filtre (Collection,Prédicat), à partir d'Apache Commons.

 87
Author: Kevin Wong, 2015-11-17 06:11:33

Le"meilleur" moyen est une demande trop large. Est-il "le plus court"? "Le plus rapide"? "Lisible"? Filtre en place ou dans une autre collection?

Le moyen le plus simple (mais pas le plus lisible) est de l'itérer et d'utiliser Iterator.méthode remove ():

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

Maintenant, pour le rendre plus lisible, vous pouvez l'envelopper dans une méthode utilitaire. Inventez ensuite une interface IPredicate, créez une implémentation anonyme de cette interface et faites quelque chose comme:

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

Où filterInPlace() itère la collection et appelle Prédicat.keepIt () pour savoir si l'instance doit être conservée dans la collection.

Je ne vois pas vraiment de justification pour faire appel à une bibliothèque tierce uniquement pour cette tâche.

 60
Author: Vladimir Dyuzhev, 2014-07-17 16:26:29

ConsidérezGoogle Collections pour un framework de collections mis à jour qui prend en charge les génériques.

MISE À JOUR: La bibliothèque Google collections est maintenant obsolète. Vous devriez utiliser la dernière version de Guava à la place. Il a toujours les mêmes extensions au framework collections, y compris un mécanisme de filtrage basé sur un prédicat.

 60
Author: Heath Borders, 2015-07-13 19:26:35

Attendre 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
Author: 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 > 10, puis 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
Author: 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 il vous donnera plus de flexibilité si vous souhaitez ajouter plus de transformations sur votre collection ou gérer les erreurs lors du filtrage.

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 le filterde RxJava peuvent être trouvés ici.

 9
Author: anon, 2016-02-14 23:25:12

La configuration:

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
Author: 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 en une seule ligne:

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

Notez que toList() est statiquement importé

 6
Author: 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.FilterIterator

Ou en utilisant la version 4 de l'organisation apache commons .Apache.commun.collections4.les itérateurs.FilterIterator

 6
Author: ykaganovich, 2014-07-16 08:43:33

, regardons comment le filtre intégré au JDK Liste et un MutableList utiliser 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 voulez filtrer les nombres inférieurs à 3, vous attendez les 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 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 des Collections Eclipse MutableLists en utilisant le Prédicats usine.

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

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

Voici une version qui n'alloue pas d'objet pour le prédicat, en utilisant la fabrique Predicates2 à la place avec la méthode selectWith qui prend un Predicate2.

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

Parfois, vous voulez 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 lambda Java 8 comme 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 {[13] } retournera deux collections, contenant les éléments sélectionnés et rejetés 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());

Remarque: Je suis un committer pour les collections Eclipse.

 5
Author: Donald Raab, 2016-02-08 04:20:22

Avec le DSL ForEach, 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 [quick, brown, jumps, over, lazy], c'est-à-dire toutes les chaînes de plus de trois caractères.

Tous les styles d'itération pris en charge par le DSL ForEach sont

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

Pour plus de détails, veuillez consulter https://www.iam.unibe.ch/scg/svn_repos/Sources/ForEach

 4
Author: akuhn, 2008-12-03 16:20:21

Les collections 2.filter (Collection,Predicate) méthode dans La bibliothèque Goyave de Google fait exactement ce que vous recherchez.

 4
Author: Kevin Wong, 2012-08-09 21:19:44

Ceci, combiné à l'absence de fermetures réelles, est mon plus grand reproche 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... la compréhension de la liste intégrée au niveau de la langue rend tout tellement plus propre. Sans ajouts au niveau de la langue, Java ne peut pas être aussi propre que beaucoup d'autres langues dans ce domaine.

Si la performance est une énorme préoccupation, Google collections est le chemin pour aller (ou écrire votre propre utilitaire de prédicat simple). La syntaxe Lambdaj est plus lisible pour certaines personnes, mais elle n'est pas aussi efficace.

Et puis il y a une bibliothèque que j'ai écrite. Je vais ignorer toutes les questions en ce qui concerne son efficacité (oui, c'est si mauvais)...... Oui, je sais que sa réflexion est clairement basée, et non je ne l'utilise pas réellement, mais cela 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
Author: 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 performante pour interroger la collection de beans Java.

Principales caractéristiques

  • Prise en charge de la collection (java.util.Collection, java.util.Carte et tableau) propriétés.
  • Prise en charge de la collection à l'intérieur de la collection de toute profondeur.
  • Prise en charge des requêtes internes.
  • Prise en charge des requêtes paramétrées.
  • Peut filtrer 1 millions d'enregistrements en quelques 100 ms.
  • Filter ( query) est donné au format json simple, c'est comme les requêtes Mangodb. En voici quelques exemples.
  • { "id":{"$chier":"10"}
    • où la propriété object id est inférieure à égale à 10.
  • {"id": {"in dans": ["0", " 100"]}}
    • où la propriété object id est 0 ou 100.
  • {"comptes":{"lineAmount":"1"}}
    • où la propriété lineItems collection de type paramétré a lineAmount égal à 1.
  • { "$et":[{"id": "0"}, {"billingAddress":{"ville":"DEL"}}]}
    • où la propriété id est 0 et billingAddress.la propriété de la ville est DEL.
  • {"lineItems": {"taxes": {"clé": {"code": "TPS"}, "valeur": {"gt gt": "1.01"}}}}
    • où la propriété de collection lineItems de type paramétré qui a des taxes la propriété de type map de type paramétré a un code égal à la valeur GST supérieure à 1,01.
  • {'$ou':[{'code':'10'},{'sku": {'$et':[{'prix':{'$dans':['20', '40']}}, {'code':'RedApple'}]}}]}
    • Sélectionnez tous les produits dont le code produit est 10 ou le prix sku en 20 et 40 et dont le code sku est "RedApple".
 2
Author: Kamran Ali Khan, 2012-04-05 10:46:58

J'ai écrit une classe itérable étendue qui prend en charge l'application d'algorithmes fonctionnels sans 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 exécutera réellement

for( int n : myList )
{
    if( n % 2 == 0 ) 
    {
        System.out.println(n);
    }
}
 2
Author: Vincent Robert, 2014-07-23 15:50:02
 2
Author: 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)

Donc 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
Author: fbokovikov, 2018-05-24 13:59:00

La solution simple pré-Java8:

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, produisant une liste plutôt que le type de la collection donnée. En outre, apporter des bibliothèques ou écrire des fonctions qui enveloppent ce code me semble exagéré à moins que la condition ne soit complexe, mais vous pouvez alors écrire une fonction pour la condition.

 1
Author: Andrew McKnight, 2014-07-03 19:15:32

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

Prend en charge 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 Java 7)

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

Regroupement de (aussi 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();

Rejoint (aussi disponible pour le Java 7)

Donné,

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

Peut être joint comme,

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
Author: Low Flying Pelican, 2014-09-03 12:59:35

Ma réponse s'appuie sur celle de Kevin Wong, ici comme un one-liner utilisant CollectionUtilsde springet une expression Java 8 lambda.

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

C'est aussi concis et lisible que toute alternative que j'ai vue (sans utiliser de bibliothèques basées sur les aspects)

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

 1
Author: vikingsteve, 2015-04-22 11:18:24

Quelques très bonnes réponses ici. Moi, j'aimerais garder les thins aussi simples et lisibles 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
Author: Lawrence, 2018-04-05 16:22:48

Utiliser java 8, spécifiquement lambda expression, vous pouvez le faire simplement comme l'exemple ci-dessous:

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

, Où pour chaque product dans myProducts collection, si prod.price>10, puis ajoutez ce produit à la nouvelle liste filtrée.

 0
Author: hd84335, 2015-12-12 21:47:55

Avec de la 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
Author: ZhekaKozlov, 2016-12-15 09:26:44

J'avais besoin de 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 actuelle. {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
Author: Fredrik Metcalf, 2017-06-15 14:28:05