2017-09-15 1 views
0

Je cherche un meilleur algorithme utilisant des flux pour imprimer les professions de tri en fonction du salaire.Regroupement et tri d'une collection avec Java 8 Streams (solution propre)

La classe java est:

public class Rh { 

private int id; 
private String nome; 
private Double salario; 
private String profissao; 
private String cidade; 
private String uf; 
private String serie; 
private Double peso; 
private String sexo; 
/* constructor and getters and setters */ 

} 

Voici le code SQL:

CREATE TABLE rh 
    (
    id serial primary key, 
    nome character varying, 
    salario numeric(9,2), 
    profissao character varying, 
    cidade character varying, 
    uf character varying, 
    serie_favorita character varying, 
    peso numeric(6,2), 
    sexo character varying 
); 

INSERT INTO rh(nome, salario, profissao, serie_favorita, peso, sexo) VALUES 
      ('Ana', '3000',  'Programador',     'GOT',  '80', 'F'); 

INSERT INTO rh(nome, salario, profissao, cidade, uf, serie_favorita, peso, sexo) VALUES 
      ('Beatriz', '2000', 'Vendedor', 'Cianorte', 'PR', 'GOT',  '65.3', 'F'); 

INSERT INTO rh(nome, salario, profissao, cidade, uf, serie_favorita, peso, sexo) VALUES 
      ('Carla', '3200', 'Vendedor', 'Mambore', 'PR', 'Smallville', '67.1', 'F'); 

INSERT INTO rh(nome, salario, profissao, cidade, uf, serie_favorita, peso, sexo) VALUES 
      ('Carlos', '1800', 'Programador', 'Floripa', 'SC', 'BB',   '82.3', 'M'); 

INSERT INTO rh(nome, salario, profissao, cidade, uf, serie_favorita, peso, sexo) VALUES 
      ('Beto', '2200', 'Barista', 'Floripa', 'SC',  'BB',   '70.15','M'); 
INSERT INTO rh(nome, salario, profissao, cidade, uf, serie_favorita, peso, sexo) VALUES 
      ('Diogo', '2400', 'Professor', 'CM', 'PR',  'GOT',  '93', 'M'); 

INSERT INTO rh(nome, salario, profissao, cidade, uf, serie_favorita, peso, sexo) VALUES 
      ('Diego', '2500', 'Biologo', 'CM', 'PR',   'GOT',  '75', 'M'); 

INSERT INTO rh(nome, salario, profissao, cidade, uf, serie_favorita, peso, sexo) VALUES 
      ('Diego', '1500', 'Fisioterapeuta', 'Mambore', 'PR', 'GOT',   '70', 'M'); 

INSERT INTO rh(nome, salario, profissao, cidade, uf, serie_favorita, peso, sexo) VALUES 
      ('Bruno', '1550', 'Médico', 'Cascavel', 'PR',  'GOT',  '88', 'M'); 

INSERT INTO rh(nome, salario, profissao, cidade, uf, serie_favorita, peso, sexo) VALUES 
      ('Fabio', '1455', 'Matemático', 'Floripa', 'SC', 'BB',  '96', 'M'); 

La requête souhaitée est:

SELECT profissao, avg(salario) FROM rh GROUP BY profissao ORDER BY avg(salario); 

En java:

List<Rh> listaRh = Arrays.asList(
    new Rh(1, "Ana", 3000.0, "Programador", null, null, "GOT", 80.0, "F"), 
    new Rh(2, "Beatriz", 2000.0, "Vendedor", "Cianorte", "PR", "GOT", 65.3, "F"), 
    new Rh(3, "Carla", 3200.0, "Vendedor", "Mambore", "PR", "SmallVille", 67.1, "F"), 
    new Rh(4, "Carlos", 1800.0, "Programador", "Floripa", "SC", "BreakingBad", 82.3, "M"), 
    new Rh(5, "Beto", 2200.0, "Barista", "Floripa", "SC", "BreakingBad", 70.15, "M"), 
    new Rh(6, "Diogo", 2400.0, "Professor", "Campo Mourão", "PR", "GOT", 93.0, "M"), 
    new Rh(7, "Diego", 2500.0, "Biólogo", "Campo Mourão", "PR", "GOT", 75.0, "M"), 
    new Rh(8, "Diego", 1500.0, "Fisioterapeuta", "Mambore", "PR", "GOT", 70.0, "M"), 
    new Rh(9, "Bruno", 1550.0, "Médico", "Cascavel", "PR", "GOT", 88.0, "M"), 
    new Rh(10, "Fabio", 1455.0, "Matemático", "Floripa", "SC", "BreakingBad", 96.0, "M") 
); 

J'ai obtenu la solution suivante en utilisant les flux:

Map<String, Double> result2 = listaRh.stream() 
    .collect(Collectors.groupingBy(
     l -> l.getProfissao(), 
     Collectors.averagingDouble(l -> l.getSalario()))); 

Map<String, Double> finalMap = new LinkedHashMap<>(); 

result2.entrySet().stream() 
    .sorted(Map.Entry.<String,Double>comparingByValue()) 
    .forEachOrdered(e -> finalMap.put(e.getKey(), e.getValue())); 

for (Map.Entry<String, Double> entry : finalMap.entrySet()) 
     System.out.println(entry.getKey()+" "+entry.getValue()); 

Ma question est ... Y at-il une solution « propre » de faire la même chose en utilisant les flux?

+1

Il n'y a pas besoin de créer ce 'finalMap' du tout,' result2.entrySet() flux() .sorted (Map.Entry.comparingByValue()) .forEachOrdered (e -> System.out.println (e.getKey() + "" + e.getValue()); ' – Holger

+0

Je pensais que vous pourriez collecter directement à un TreeMap, mais En réalité, le constructeur ne prend qu'un comparateur clé et non un comparateur d'entrée. – AjahnCharles

+2

Le tri des ensembles de résultats est quelque chose qu'une base de données fait bien. N'essayez pas de conduire un clou avec des coupe-ongles. – DwB

Répondre

-1

est ici une solution par SteamEx forked par moi

StreamEx.of(rhList) 
    .groupByToEntry(Rh::getProfissao, Fn.averagingDouble(Rh::getSalario)) 
    .sortedByValue(Fn.naturalOrder()).toMap(LinkedHashMap::new); 
+0

Merci de nous avoir présenté cette bibliothèque, je vais la regarder attentivement. –

1

Une solution plus propre l'utilisation des flux pourrait bien inclure:

  • références Méthode: par exemple Rh::getProfissao au lieu de l -> l.getProfissao()
  • L'utilisation d'un Collector au lieu de construire manuellement la carte des résultats
  • importations statiques

En utilisant les idées ci-dessus avec votre exemple:

import static java.util.Map.Entry.comparingByValue; 
import static java.util.stream.Collectors.averagingDouble; 
import static java.util.stream.Collectors.groupingBy; 
import static java.util.stream.Collectors.toMap; 

...

Map<String, Double> result2 = listaRh.stream() 
    .collect(groupingBy(Rh::getProfissao, averagingDouble(Rh::getSalario))); 

Map<String, Double> finalMap = result2.entrySet().stream() 
    .sorted(comparingByValue()) 
    .collect(toMap(
     Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a, LinkedHashMap::new)); 

for (Map.Entry<String, Double> entry : finalMap.entrySet()) 
    System.out.println(entry.getKey() + " " + entry.getValue()); 

Si vous ne le faites pas besoin finalMap en plus pour l'impression de son contenu, vous pouvez éviter d'utiliser le LinkedHashMap et collecteur toMap entièrement.

result2.entrySet().stream() 
    .sorted(comparingByValue()) 
    .forEach(entry -> System.out.println(entry.getKey() + " " + entry.getValue())); 
+0

Merci @Kunda !!! –