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

Java Discussion :

problème collector sur mesure


Sujet :

Java

  1. #1
    Membre chevronné

    Profil pro
    Inscrit en
    Décembre 2011
    Messages
    974
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2011
    Messages : 974
    Points : 1 825
    Points
    1 825
    Par défaut problème collector sur mesure
    Bonjour,

    j'ai plusieurs centaines de données dans un fichier sous la forme:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    "code_barre,quantité"

    Dans le fichier, il y a plusieurs lignes avec une chaîne comprenant le même "code_barre" et des "quantité" différentes. Mon but de de regrouper l'ensemble dans une Map<String,Integer> où la clé est le "code_barre" unique et la valeur est la somme des quantités trouvées.

    Pour ce faire, j'ai pensé faire le boulot via un Collector du type:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
     
     
    public class MonCollectorData implements Collector<String, Map<String,Integer>, Map<String,Integer>> {
     
    	@Override
    	public BiConsumer<Map<String,Integer>, String> accumulator() {
     
    		return (map,st) ->{
    			String[] tempo = st.split(",");
    			String cle = tempo[0].trim();
    			Integer val = null ; 
     
    			try {
    				val = Integer.valueOf(tempo[1].trim());
    			}
    			catch(NumberFormatException e) {
    				val = Integer.valueOf("0");
    			}
    			map.put(cle, val);
    		};
    	}
    	@Override
    	public Set<Characteristics> characteristics() {
    		return EnumSet.of(Characteristics.UNORDERED);
    	}
     
    	@Override
    	public BinaryOperator<Map<String,Integer>> combiner() {
     
    		return (map1, map2)-> { 
     
    				map1.forEach((k, v) -> map2.merge(k, v, Integer::sum));
     
    		    return map2;
    		};
    	}
     
    	@Override
    	public Function<Map<String,Integer>, Map<String,Integer>> finisher() {
    		return Function.identity();
    	}
     
    	@Override
    	public Supplier<Map<String,Integer>> supplier() {		
    		return HashMap::new;
    	}
    }

    Cependant, un faisant des tests comme ci-dessous, je n'obtiens le résultat espéré (idem avec les données du fichier où le Stream<String> est créé cette fois-ci par la lecture des données):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    String[] tab = {"val1,41","val2,9","val3,5","val3,9","val2,2","val1,35"};
     
    resMap = Arrays.stream(tab).collect(new MonCollectorData());
     
    resMap.forEach((k,v) ->  System.out.println("clé : "+k+"\t"+"val : "+v));
    Le résultat est:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    clé : val3	val : 9
    clé : val2	val : 2
    clé : val1	val : 35
    et devrait être

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    clé : val3	val : 14
    clé : val2	val : 11
    clé : val1	val : 76
    Après une journée de lecture, relecture du code, test, et débogage , je ne trouve pas l'erreur: pour quoi la somme ne se fait pas au niveau de la fusion des Map ?

    merci pour votre aide

  2. #2
    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
    Hello,

    la somme se fait très bien au niveau de la fusion des maps, mais ça n'a pas d'importance puisque ton stream n'est pas multithreadé et ne va rien fusionner du tout.

    le problème c'est ton accumulator, qui n'accumule rien du tout. Il met juste la dernière valeur trouvée à la place de ce qu'il y avait avant.

    ... et je me demande ce que tu as bien pu déboguer sans te rendre compte qu'il n'y a pas de fusion de maps
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,

    L'Accumulator sert à accumuler les résultats : c'est lui qui doit s'occuper de faire la somme des éléments, pour accumuler.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    		class MonCollectorData implements Collector<String, Map<String,Integer>, Map<String,Integer>> {
     
    			@Override
    			public BiConsumer<Map<String,Integer>, String> accumulator() {
     
    				return (map,st) ->{
    					String[] tempo = st.split(",");
    					String cle = tempo[0].trim();
    					Integer val = null ; 
     
    					try {
    						val = Integer.valueOf(tempo[1].trim());
    					}
    					catch(NumberFormatException e) {
    						val = 0;
    					}
     
    					final Integer fval=val;
    					map.compute(cle, (k1,v1)-> v1==null?fval:v1+fval); // on accumule les valeurs pour la clef
     
    				};
    			}
    			@Override
    			public Set<Characteristics> characteristics() {
    				return EnumSet.of(Characteristics.UNORDERED);
    			}
     
    			@Override
    			public BinaryOperator<Map<String,Integer>> combiner() {
     
    				return (map1, map2)-> { 
     
    					map1.forEach((k, v) -> map2.merge(k, v, Integer::sum));
     
    			    return map2;
    			}
     
    			@Override
    			public Function<Map<String,Integer>, Map<String,Integer>> finisher() {
    				return Function.identity();
    			}
     
    			@Override
    			public Supplier<Map<String,Integer>> supplier() {		
    				return HashMap::new;
    			}
    		}
    Sinon, on peut faire ce que tu veux sans écrire un Collector :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    String[] tab = {"val1,41","val2,9","val3,5","val3,9","val2,2","val1,35"};
     
     
    Map<String, Integer>  result = Arrays.stream(tab).map(v->v.split(","))
    						.collect(Collectors.groupingBy(t->t[0]))
    						.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
    								entry-> entry.getValue()
    								.stream().map(t->t[1]).map(Integer::valueOf).reduce(Integer::sum).orElse(0)));
     
     
    System.out.println(result);
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

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

Discussions similaires

  1. Problème droit sur un tablespace
    Par wazar dans le forum Administration
    Réponses: 11
    Dernier message: 05/01/2010, 15h12
  2. problème écriture sur un fichier
    Par drinkmilk dans le forum MFC
    Réponses: 4
    Dernier message: 24/06/2007, 00h08
  3. Problème innerHTML sur div !!!
    Par aburner dans le forum Général JavaScript
    Réponses: 5
    Dernier message: 27/01/2005, 09h23
  4. [CR8] Problème tableau sur plusieurs pages???
    Par christophe28 dans le forum SAP Crystal Reports
    Réponses: 5
    Dernier message: 02/11/2004, 15h46
  5. [MFC] Problème pointeur sur une classe
    Par mick74 dans le forum MFC
    Réponses: 7
    Dernier message: 14/04/2004, 14h17

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