簡體   English   中英

使用Java 8 Streams對集合進行分組和排序(干凈的解決方案)

[英]Grouping and Sorting a Collection with Java 8 Streams (clean solution)

我正在尋找更好的算法,使用流來根據薪水打印分類職業。

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

我的問題是...是否有一種“干凈”的解決方案可以使用流執行相同的操作?

僅使用流的更清潔的解決方案可能包括:

  • 方法引用:例如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()));

這是我分叉SteamEx的解決方案

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM