IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

avec Java Discussion :

Question à propos la méthode reduce de stream()


Sujet :

avec Java

  1. #1
    Débutant  
    Inscrit en
    Mai 2006
    Messages
    705
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 705
    Points : 117
    Points
    117
    Par défaut Question à propos la méthode reduce de stream()
    Bonsoir TLM,

    Je commence à tester le Java 8 , et j'ai les 3 instructions suivantes:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    String names = employees.stream().map(e->e.getName()).reduce("", (a,b)->a+" - "+b);
     
    Integer ageTotal = persons.stream().reduce(0, (somme,p)->somme+=p.getAge(),(s1,s2)->s1+s2);
     
    persons
        .stream()
        .reduce((p1, p2) -> p1.age > p2.age ? p1 : p2)
        .ifPresent(System.out::println);
    1- C'est quoi la différence entre un reduce avec 2 paramètres et reduce avec 3 paramètres?

    2- Le troisième argument dans la deuxième instruction ((s1,s2)->s1+s2) sert à faire quoi?

    3- D'après mes connaissances, Reduce est une opération terminale, pourquoi alors mettre ifPresent au final dans la troisième instruction?

    Merci pour votre aide en avance!

  2. #2
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    3 - car cette version de reduce() renvoie un Optional<T> au lieu d'un Stream<T>. Le ifPresent() (qui est une méthode de Optional<T>) est donc invoqué sur le résultat du reduce().
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  3. #3
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    1 - il existe 3 versions de reduce(). A noter que la doc indique le code équivalent aux appels de ces méthodes :

    Optional<T> reduce(BinaryOperator<T> accumulator) -

    C'est la version que tu utilises, si jamais le flux est vide ça renverra Optional.EMPTY.
    C'est la même chose que faire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    boolean foundAny = false;
    T result = null;
    for (T element : this stream) {
        if (!foundAny) {
            foundAny = true;
            result = element;
        } else 
            result = accumulator.apply(result, element);
    }
    return foundAny ? Optional.of(result) : Optional.empty();
    T reduce(T identity, BinaryOperator<T> accumulator) -

    Si jamais le flux est vide ça renverra identity.
    A noter que identity fait partie du calcul de l'accumulateur et est donc pris en compte lorsque le flux n'est pas vide (donc souvent on met 0 quand on travaille avec des nombres).
    C'est la même chose que faire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    T result = identity;
    for (T element : this stream)
        result = accumulator.apply(result, element)
    return result;
    U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner) -

    C'est la même chose que faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    U result = identity;
    for (T element : this stream)
        result = accumulator.apply(result, element)
    return result;
    MAIS cette variante de reduce() peut ne pas s’exécuter séquentiellement (elle peut tourner en parallèle). Pour que son résultat soit correct, il faut donc que de tout temps combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  4. #4
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    Citation Envoyé par L'aigle de Carthage Voir le message
    2- Le troisième argument dans la deuxième instruction ((s1,s2)->s1+s2) sert à faire quoi?
    Quel troisième argument ? Je ne vois que s1 et s2 ici.
    s1 est le résultat précédemment calculé et s2 est l’élément actuel du flux, voir code équivalent de cette variante plus haut.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  5. #5
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Le 3e argument de reduce(). L'identity, l'accumulator, et enfin le combiner.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Débutant  
    Inscrit en
    Mai 2006
    Messages
    705
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 705
    Points : 117
    Points
    117
    Par défaut
    Merci pour vos réponses, ça m'aide beaucoup!

    Mais reste une chose que je n'arrive pas à le comprendre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    String names = employees.stream().map(e->e.getName()).reduce("", (a,b)->a+" - "+b);
     
    Integer ageTotal = persons.stream().reduce(0, (somme,p)->somme+=p.getAge(),(s1,s2)->s1+s2);
    1- Est ce qu'on utlise le reduce avec 2 paramètres dans le cas de manipulation de String, et 3 paramètres dans le cas d'entiers?

    2-
    s1 est le résultat précédemment calculé et s2 est l’élément actuel du flux, voir code équivalent de cette variante plus haut.
    Est ce que somme ne représente pas le résultat déjà calculé ici? pk l'utilisation de s1 et s2?

    J'espère que vous avez compris ma requête! thx!

  7. #7
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    Tu peux utiliser n'importe lequel des 3 variantes dans le contexte qui te convient. La 3eme variante est adaptée à un traitement parallèle du flux comme indiqué dans sa doc. Les deux premières méthodes sont adaptées à des traitement séquentiels.

    Sachant que la méthode collect(Collectors.joining(séparateur, prefixe, suffixe)) marche aussi très bien pour concaténer les strings et fait grosso modo la même chose. Et qu'on peut tout aussi bien créer un collecteur pour ajouter des Integer entre eux

    PS : rappel pour manipuler des entier littéraux on va plutôt utiliser un IntStream qu'un Stream<Integer>.

    Non, la somme ici est l'action à effectuer en fonction des deux paramètres en entrée ; comme je le disais :
    • s1 est le résultat précédemment calculé
    • s2 est l’élément actuel du flux, voir code équivalent de cette variante plus haut.


    Donc pour un élément à l'index n du flux on va avoir deux paramètres :
    • Sn-1 la somme précédente
    • Vn la valeur actuelle


    Donc on fait Sn-1 + Vn. Il se trouve juste qu'au tout premier élément on a pas de somme précédente donc dans la variante de la méthode sans argument, la première somme est égale au 1er élément, c'est ce qui initialise la valeur du résultat :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    S0 = V0
    S1 = S0 + V1 = V0 + V1
    S2 = S1 + V2 = V0 + V1 + V2
    [...]
    S2 = Sn-1 + Vn = V0 + V1 + V2 + ... + Vn
    [...]
    Sfinal = V0 + V1 + V2 + ... + Vn + ... + Vfinal
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  8. #8
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,

    Citation Envoyé par L'aigle de Carthage Voir le message
    1- Est ce qu'on utlise le reduce avec 2 paramètres dans le cas de manipulation de String, et 3 paramètres dans le cas d'entiers?
    Pas forcément.
    En fait les deux premières versions de reduce() fonctionnent uniquement avec le type T de ton Stream : reduce(BinaryOperator<T>) et reduce(T identity, BinaryOperator<T> accumulator).
    C'est à dire que le type de retour est du même type que le type des éléments de ton Stream.

    La troisième version de reduce() est paramétré par un second type U, qui permet d'avoir un résultat de type différent de celui du Stream : reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)


    Citation Envoyé par L'aigle de Carthage Voir le message
    Est ce que somme ne représente pas le résultat déjà calculé ici? pk l'utilisation de s1 et s2?
    On est typiquement dans le cas précité : le type du Stream est différent de celui de ton résultat, et donc il faut utiliser la troisième version de reduce().

    Ton code est tout à fait correct :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Integer ageTotal = persons.stream().reduce(0, (somme,p)->somme+=p.getAge(),(s1,s2)->s1+s2);
    Et le troisième paramètre est primordiale lorsque le flux exécute en parallèle.
    => Le premier paramètre (identity) représenter la valeur initiale (0) dans ton cas.
    => Le second paramètre (accumulator) permet d'accumuler les objets de ton flux dans le résultat (cad rajouter l'age de la personne).
    => Le troisième paramètre (combiner) permet de gérer l’exécution en parallèle, et permet de combiner deux résultats.

    En effet si le flux s’exécute en parallèle, il va être découpé en plusieurs petits bouts qui seront calculé en parallèles.
    Le "combiner" permet donc de récupérer chacun des résultats et et les recombiner pour obtenir le résultat final.



    A noter quand même que pour une somme tu aurais pu utiliser mapToInt() sur ton attribut pour obtenir un IntStream comportant des méthodes plus adaptées :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int age = persons.stream().mapToInt(Person::getAge).sum();


    Enfin, la méthode reduce() n'est pas très adapté pour la concaténation de String.
    Et ton code n'est pas très bon pour deux raisons car il génère une nouvelle String à chaque concaténation, ce qui peut s'avérer catastrophique sur de grande quantité de données :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    String names = employees.stream().map(e->e.getName()).reduce("", (a,b)->a+" - "+b);
    Il sera plus approprié d'utiliser un "collector", qui fonctionne sur le même principe mais dont le résultat est prévu pour s'accumuler dans un objet modifiable.
    En gros çà donnerait ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
          String names = employees.stream()
            .collect(StringBuilder::new,
                     (sb,e) -> sb.append(" - ").append(e.getName()),
                     (sb1, sb2) -> sb1.append(sb2)
            ).toString();
    A noter qu'il y a le même "bug" que dans ton code initial : le résultat commence par ton séparateur " - ", et il faudrait gérer ce cas.

    Mais en fait il existe déjà des "collectors" pour concaténer des chaines (ainsi que pour d'autres cas courant).
    => Voir la classe Collectors !

    Ce qui donne tout simplement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
          String names = employees.stream()
            .map(e->e.getName())
            .collect(Collectors.joining(" - "));

    a++

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 7
    Dernier message: 24/02/2012, 20h51
  2. [Méthode] Des question à propos du MVC
    Par NiRaDo dans le forum MVC
    Réponses: 4
    Dernier message: 20/04/2009, 19h42
  3. Question à propos de la méthode display() d'OpenGL
    Par choko83 dans le forum OpenGL
    Réponses: 7
    Dernier message: 02/05/2008, 16h03
  4. Petite question à propos d'une requete
    Par ViBy dans le forum Langage SQL
    Réponses: 4
    Dernier message: 15/09/2004, 12h21
  5. Une question à propos des thread
    Par tscoops dans le forum C++Builder
    Réponses: 4
    Dernier message: 07/11/2003, 14h03

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo