web-dev-qa-db-fra.com

Quelle est la meilleure façon de diviser une collection en 2 collections différentes?

J'ai un ensemble de chiffres:

 Set<Integer> mySet = [ 1,2,3,4,5,6,7,8,9]

Je veux le diviser en 2 ensembles de cotes et d'unités.

Ma façon était d'utiliser le filtre deux fois:

Set<Integer> set1 = mySet.stream().filter(y -> y % 2 == 0).collect(Collectors.toSet())
Set<Integer> set2 =mySet.stream().filter(y -> y % 2 != 0).collect(Collectors.toSet())

Je n'aime pas cette solution car je passe deux fois sur l'ensemble.

Existe-t-il un moyen plus intelligent de le faire?

35
user1386966
Map<Boolean, List<Integer>> partitioned = 
    set.stream().collect(Collectors.partitioningBy(x -> x%2 == 0));

Les éléments de partitioned.get(true) sont pairs; les éléments dans partitioned.get(false) sont impairs.

Contrairement à cela en utilisant groupingBy, il est garanti que les listes true et false seront présentes dans la carte même si elles sont vides. (Non documenté dans Java 8, mais c'était vrai; Java 9 l'indique maintenant explicitement).

38
Andy Turner

Boucle simple et si/sinon serait une solution propre et simple

Set<Integer> setEven = new HashSet<>();
Set<Integer> setOdd = new HashSet<>();

for (Integer val : mySet) {
    if (val % 2 == 0)
        setEven.add(val);
    else
        setOdd.add(val);
}

Ou utiliser un opérateur ternaire fonctionne bien pour simplifier encore plus le code

for(Integer val : mySet) {
    ((val % 2 == 0) ? setEven : setOdd).add(val);
}
13
RAZ_Muh_Taz

Vous pouvez utiliser Collectors#partitioningBy comme ci-dessous.

Map<Boolean,List<Integer>> evenOddMap  = mySet.stream().collect(Collectors.partitioningBy(e -> e % 2 == 0));
System.out.println("Even : "+evenOddMap.get(true));
System.out.println("Odd : "+evenOddMap.get(false));
13
Amit Bera

Vous pouvez utiliser Collectors.partitioningBy :

        Map< Boolean, Set<Integer> > map =
        mySet.stream().collect( Collectors.partitioningBy( y -> y % 2 == 0, 
        Collectors.toSet() ) );

        Set<Integer> odds = map.get(Boolean.TRUE);
        Set<Integer> evens = map.get(Boolean.FALSE);

MODIFIER:

Je vois qu'il y a quelques réponses similaires. La légère différence ici est qu'elle montre comment obtenir les collections en tant que Set au lieu de List au cas où OP le souhaiterait de cette façon.

11
tsolakp

Si vous disposez déjà de collections pour contenir des valeurs, ce qui suit peut être une solution.

data.stream().forEach(x -> {
if(x%2==0){
//add to collection holding even nums
} else {
//add to collection holding odd nums
}
})
1
Amar Dev

Vous pouvez utiliser un groupingBy

public void test(String[] args) {
    Integer[] test = {1,2,3,4,5,6,7,8,9};
    Map<Integer, List<Integer>> evenOdd = Arrays.stream(test).collect(Collectors.groupingBy(i -> i & 1));
    Set<Integer> evens = new HashSet<>(evenOdd.get(0));
    Set<Integer> odds = new HashSet<>(evenOdd.get(1));
    System.out.println("Evens "+evens+" Odds "+odds);
}
0
OldCurmudgeon