分组和减少元素
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)
我认为这两种方法都可以进一步优化,特别是查询。
可以用 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
是您的输出类型 String
,T
是您的输入类型 Contract
。
我的数据库正在返回这样的数据集
结果
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)
我认为这两种方法都可以进一步优化,特别是查询。
可以用 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
是您的输出类型 String
,T
是您的输入类型 Contract
。