分组和减少元素

Group and reduce Elements

我的数据库正在返回这样的数据集

结果

id  Percentage
1    20
1    15
2    30
2    40
3    10

映射到合同实体

class Contract{
    private Integer id;
    private Double percentaje;
    ....
}

我的预期结果是 Map

例如:1, 20% 15%

第一个值是id,第二个是百分比的concat

这是我目前的方法

Map<Integer, String> res = result.stream().collect(Collectors.groupingBy(Contract::getId,
Collectors.reducing(0, Contract::getPercentage, (a, b) -> String.join("% ", a.toString(), b.toString()))
    );

intellij 显示错误

Bad return type in lambda expression: String cannot be converted to Number & Comparable<? extends Number & Comparable<?>>

知道如何解决这个问题,谢谢

请注意,这也可以直接从数据库完成,但这适用于 Java 8.

    List<Contract> result = new ArrayList<>();
    result.add(new Contract(1, 20));
    result.add(new Contract(1, 15));
    result.add(new Contract(2, 30));
    result.add(new Contract(2, 40));
    result.add(new Contract(3, 10));
        
    Map<Integer, String> mapped = new HashMap<>();
        
    result.stream().collect(Collectors.groupingBy(Contract::getId)).forEach((k, l) -> 
        mapped.put(k, l.stream().map(c -> c.getPercentaje().toString().concat("% ")).collect(Collectors.joining())
        )
    );
        
    mapped.forEach((k, v) -> System.out.println(k + ", " + v));

Collectors.groupingBy 的结果是 Map<Integer, List<Contract>>。虽然应该可以做 'one liner',但我认为循环遍历第一个地图并将结果“减少”添加到不同的地图更容易理解。

为了完整起见,查询MySQL中的这个结果如下

SELECT t1.id, GROUP_CONCAT(DISTINCT CONCAT(t2.percentaje, '%') SEPARATOR ' ') 
FROM table1 t1 
    JOIN table1 t2 ON t2.id = t1.id
GROUP BY t1.id;

GROUP_CONCAT 对于这些案例场景来说是一个非常有用的函数。您可以在 the documentation for it 中进一步阅读。 (感谢 hc_dev)

我认为这两种方法都可以进一步优化,特别是查询。

Javafiddlehere。 SQL fiddle here.

可以用 Collectors.mapping() 作为 Collectors.groupingBy() 的下游来完成:

Map<Integer, String> result = result.stream()
                .collect(Collectors.groupingBy(Contract::getId,
                        Collectors.mapping(c -> c.getPercentage().toString() + "%", Collectors.joining(" "))));

您的问题:

Bad return type in lambda expression: String cannot be converted to Number & Comparable>

可能与 Collectors.reducing 通话。

应该是:

Collectors.reducing(
   "",  // Contract to default String
   contract -> contract.getPercentage().toString() + "%",  // mapping Contract to String 
   (a, b) -> String.join(" ", a, b)  // reducing two ready-mapped Strings
)

比较Collectors.reducing的声明:

public static <T,U> Collector<T,?,U> reducing(
   U identity,
   Function<? super T,? extends U> mapper,
   BinaryOperator<U> op
)

其中 U 是您的输出类型 StringT 是您的输入类型 Contract