2017-09-19 1 views
0

J'ai une table de hachage sous la formeTraitement HashMap en utilisant Java 8 API Stream

Map<String, Map<String,Double> 

je dois traiter et créer un autre ayant la même structure.

Après un échantillon pour expliquer le but

INPUT HASH TABLE 
---------------------------- 
|  | 12/7/2000 5.0 | 
| id 1 | 13/7/2000 4.5 | 
|  | 14/7/2000 3.4 | 
    ... 
| id N |  ....  | 

OUTPUT HASH TABLE 
| id 1 | 1/1/1800 max(5,4.5,3.4) | 
    ...    ... 

En particulier, la sortie doit avoir les mêmes touches (ID1, ..., id n) La table de hachage interne doit avoir une clé fixe (1/1/1800) et une valeur traitée.

Mon code actuel (ne fonctionne pas):

output = input.entrySet() 
         .stream() 
         .collect(
           Collectors.toMap(entry -> entry.getKey(), 
             entry -> Collectors.toMap(
               e -> "1/1/2000", 
               e -> { 
              // Get input array 
              List<Object> list = entry.getValue().values().stream() 
                .collect(Collectors.toList()); 

              DescriptiveStatistics stats = new DescriptiveStatistics(); 

              // Remove the NaN values from the input array 
              list.forEach(v -> { 
               if(!new Double((double)v).isNaN()) 
                stats.addValue((double)v); 
              }); 

              double value = stats.max();       

              return value; 
             })); 

Où est le problème?

Merci

+2

Quelle est l'erreur que vous obtenez? – procrastinator

+0

Impossible de convertir la carte en carte Fab

Répondre

3

La question tente d'appeler Collectors.toMap un second type dans la première Collectors.toMap. Collectors.toMap doit être passé à une méthode qui accepte un Collector.

est ici un moyen d'atteindre ce que vous voulez:

Map<String, Map<String,Double>> 
output = input.entrySet() 
       .stream() 
       .collect(Collectors.toMap(e -> e.getKey(), 
             e -> Collections.singletonMap (
              "1/1/1800", 
              e.getValue() 
              .values() 
              .stream() 
              .filter (d->!Double.isNaN (d)) 
              .mapToDouble (Double::doubleValue) 
              .max() 
              .orElse(0.0)))); 

Notez qu'il n'y a pas besoin d'une deuxième Collectors.toMap. Les Map s internes de votre sortie ont chacun une seule entrée, vous pouvez donc utiliser Collections.singletonMap pour les créer.

+0

Et de filtrer pour! IsNan. – DodgyCodeException

+0

L'opération à appeler (max, sum, ...) doit être appelée par réflexion. J'ai donc besoin d'effectuer un traitement sur la table de hachage interne. J'utilise la bibliothèque Apache Commons Math (voir la variable stats) – Fab

+0

@DodgyCodeException Merci. Ajouté le filtre. – Eran

0

Votre code d'origine peut être résolu en utilisant Collections.singletonMap au lieu de Collectors.toMap

Map<String, Map<String,Double>> output = input.entrySet() 
       .stream() 
       .collect(
         Collectors.toMap(entry -> entry.getKey(), 
          entry -> { 
           // Get input array 
           List<Object> list = entry.getValue().values().stream() 
             .collect(Collectors.toList()); 

           DescriptiveStatistics stats = new DescriptiveStatistics(); 

           // Remove the NaN values from the input array 
           list.forEach(v -> { 
            if(!new Double((double)v).isNaN()) 
             stats.addValue((double)v); 
           }); 

           double value = stats.max();       

           return Collections.singletonMap("1/1/2000", value); 
          })); 

Ou faire le Collectors.toMap emboîtée une partie d'une opération de flux réel

Map<String, Map<String,Double>> output = input.entrySet() 
       .stream() 
       .collect(Collectors.toMap(entry -> entry.getKey(), 
          entry -> Stream.of(entry.getValue()).collect(Collectors.toMap(
            e -> "1/1/2000", 
            e -> { 
           // Get input array 
           List<Object> list = e.values().stream() 
             .collect(Collectors.toList()); 

           DescriptiveStatistics stats = new DescriptiveStatistics(); 

           // Remove the NaN values from the input array 
           list.forEach(v -> { 
            if(!new Double((double)v).isNaN()) 
             stats.addValue((double)v); 
           }); 

           double value = stats.max();       

           return value; 
          })))); 

bien que ce soit calme une solution baroque. Cela dit, vous devez savoir qu'il existe le DoubleSummaryStatistics standard rendant DescriptiveStatistics inutile, cependant, les deux sont inutiles si vous voulez seulement obtenir la valeur max.

En outre, List<Object> list = e.values().stream().collect(Collectors.toList()); pourrait être simplifié pour List<Object> list = new ArrayList<>(e.values()); si un List est vraiment nécessaire, mais ici, Collection<Double> list = e.values(); serait suffisant, et en tapant la collection avec Double au lieu de Object fait le type ultérieur jette inutile.

L'utilisation de ces améliorations pour la première variante, vous obtiendrez

Map<String, Map<String,Double>> output = input.entrySet() 
      .stream() 
      .collect(
        Collectors.toMap(entry -> entry.getKey(), 
         entry -> { 
          Collection<Double> list = entry.getValue().values(); 
          DoubleSummaryStatistics stats = new DoubleSummaryStatistics(); 
          list.forEach(v -> { 
           if(!Double.isNaN(v)) stats.accept(v); 
          }); 
          double value = stats.getMax();       
          return Collections.singletonMap("1/1/2000", value); 
         })); 

Mais, comme on dit, DoubleSummaryStatistics est encore plus que nécessaire pour obtenir le maximum:

Map<String, Map<String,Double>> output = input.entrySet() 
      .stream() 
      .collect(Collectors.toMap(entry -> entry.getKey(), 
             entry -> { 
              double max = Double.NEGATIVE_INFINITY; 
              for(double d: entry.getValue().values()) 
               if(d > max) max = d; 
              return Collections.singletonMap("1/1/2000", max); 
             })); 

Notez que double comparaisons toujours évaluer à false si au moins une valeur est NaN, donc en utilisant le bon opérateur, à savoir"Valeur possible NaN"> "courant max jamais NaN", nous n'avons pas besoin d'une condition supplémentaire. Maintenant, vous pouvez remplacer la boucle par une opération de flux et vous finirez par Eran’s solution. Le choix t'appartient.