使用Java 8 Streams对集合进行分组和排序(清洁解决方案)

时间:2017-09-15 13:10:02

标签: java java-8 java-stream

我正在寻找更好的算法,使用流来根据工资打印排序职业。

java类是:

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 */

}

以下是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');

所需的查询是:

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

在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")
);

我使用流获得了以下解决方案:

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());

我的问题是......是否有&#34;清洁&#34;解决方案使用流做同样的事情?

2 个答案:

答案 0 :(得分:1)

仅使用流的清洁解决方案可能包括:

  • 方法参考:例如Rh::getProfissao代替l -> l.getProfissao()
  • 使用Collector代替手动构建结果地图
  • 静态导入

将上述想法与您的示例结合使用:

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());

除了打印内容之外,如果您不需要finalMap,则可以完全避免使用LinkedHashMap和toMap收集器:

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

答案 1 :(得分:-1)

以下是我SteamEx forked的解决方案

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