这是我在Group, Sum byType then get diff using Java streams上的上一个问题的延续。
根据建议,我应该发布一个单独的帖子而不是更新原始帖子。
因此,在我之前的一系列问题中,我已经实现了这个目标,现在,已经实现了这一目标。
背景:
我有以下数据集
Sample(SampleId=1, SampleTypeId=1, SampleQuantity=5, SampleType=ADD),
Sample(SampleId=2, SampleTypeId=1, SampleQuantity=15, SampleType=ADD),
Sample(SampleId=3, SampleTypeId=1, SampleQuantity=25, SampleType=ADD),
Sample(SampleId=4, SampleTypeId=1, SampleQuantity=5, SampleType=SUBTRACT),
Sample(SampleId=5, SampleTypeId=1, SampleQuantity=25, SampleType=SUBTRACT)
Sample(SampleId=6, SampleTypeId=2, SampleQuantity=10, SampleType=ADD),
Sample(SampleId=7, SampleTypeId=2, SampleQuantity=20, SampleType=ADD),
Sample(SampleId=8, SampleTypeId=2, SampleQuantity=30, SampleType=ADD),
Sample(SampleId=9, SampleTypeId=2, SampleQuantity=15, SampleType=SUBTRACT),
Sample(SampleId=10, SampleTypeId=2, SampleQuantity=35, SampleType=SUBTRACT)
我目前正在使用这个:
sampleList.stream()
.collect(Collectors.groupingBy(Sample::getTypeId,
Collectors.summingInt(
sample -> SampleType.ADD.equalsIgnoreCase(sample.getSampleType())
? sample.getSampleQuantity() :
-sample.getSampleQuantity()
)));
还有这个
sampleList.stream()
.collect(Collectors.groupingBy(Sample::getSampleTypeId,
Collectors.collectingAndThen(
Collectors.groupingBy(Sample::getSampleType,
Collectors.summingInt(Sample::getSampleQuantity)),
map -> map.getOrDefault(SampleType.ADD, 0)
- map.getOrDefault(SampleType.SUBTRACT, 0))));
作为获得所需输出以在Map<Long, Integer>
{1=15, 2=10}
有了这个,我想知道,如果这可以扩展到更多的东西。
首先,我怎样才能将其作为Map<String, Integer>
而不是原始Map<Long, Integer>
返回。基本上,对于SampleTypeId; 1指HELLO,2指WORLD。
所以我需要一个.map
(或者其他函数)来通过调用函数convertType(sampleTypeId)
来将数据从1转换为HELLO,将2转换为WORLD。因此预期的输出将为{"HELLO"=15, "WORLD"=10}
。是对的吗?我该如何编辑当前建议的解决方案?
最后,我想知道是否也可以将其返回到Object而不是Map
。所以,让我说我有一个对象; SummaryResult with (String) name and (int) result
。因此,它返回List<SummaryResult>
而不是原始Map<Long, Integer>
。如何使用.map
(或其他)功能执行此操作?或者还有其他方法吗?预期的产出将是这条线。
SummaryResult(name="hello", result=15),
SummaryResult(name="world", result=10),
非常感谢@M先前给出的解释。普罗霍洛夫。
更新
更新到
后sampleList.stream()
.collect(Collectors.groupingBy(sample -> convertType(sample.getSampleTypeId()),
Collectors.collectingAndThen(
Collectors.groupingBy(Sample::getSampleType,
Collectors.summingInt(Sample::getSampleQuantity)),
map -> map.getOrDefault(SampleType.ADD, 0)
- map.getOrDefault(SampleType.SUBTRACT, 0))));
private String convertType(int id) {
return (id == 1) ? "HELLO" : "WORLD";
}
答案 0 :(得分:2)
对于第一部分,考虑到你有某个方法
String convertType(int typeId)
您只需要从此
更改第一个分类器groupingBy(SampleType::getTypeId)
到这个
groupingBy(sample -> convertType(sample.getTypeId()))
其他一切都保持不变。
后期类型有点棘手,技术上并没有从它作为流相关解决方案中受益。
你需要的是:
public List<SummaryResult> toSummaryResultList(Map<String, Integer> resultMap) {
List<SummaryResult> list = new ArrayList<>(resultMap.size());
for (Map.Entry<String, Integer> entry : resultMap.entrySet()) {
String name = entry.getKey();
Integer value = entry.getValue();
// replace below with construction method you actually have
list.add(SummaryResult.withName(name).andResult(value));
}
return list;
}
您可以将此作为收集器组合的一部分,您的整个收集器将被包含在collectingAndThen
调用中:
collectingAndThen(
groupingBy(sample -> convertType(sample.getTypeId()),
collectingAndThen(
groupingBy(Sample::getSampleType,
summingInt(Sample::getSampleQuantity)),
map -> map.getOrDefault(SampleType.ADD, 0)
- map.getOrDefault(SampleType.SUBTRACT, 0))),
result -> toSummaryResultList(result))
然而,正如你所看到的,它是整个收集器被包裹起来,所以我的眼睛对上面的版本没有任何实际的好处,更简单,更容易遵循(至少对我来说)使用的版本中间变量,但不是代码之墙:
// do the whole collecting thing like before
Map<String, Integer> map = sampleList.stream()
.collect(Collectors.groupingBy(sample -> convertType(sample.getTypeId()),
Collectors.collectingAndThen(
Collectors.groupingBy(Sample::getSampleType,
Collectors.summingInt(Sample::getSampleQuantity)),
map -> map.getOrDefault(SampleType.ADD, 0)
- map.getOrDefault(SampleType.SUBTRACT, 0))));
// return the "beautified" result
return toSummaryResultList(map);
上面要考虑的另一点是:convertType
方法会被sampleList
中的元素调用多次,所以如果convertType
调用是&#34;重&#34 ; (例如,使用数据库或IO),然后最好将其作为toSummaryResultList
转换的一部分进行调用,而不是作为流元素分类器。在这种情况下,您将从Map<Integer, Integer>
类型的地图中收集,并在循环中使用convertType
。我不会考虑添加任何代码,因为我认为这个变化是微不足道的。
答案 1 :(得分:0)
你确实可以使用map()函数
sampleList.stream()
.collect(Collectors.groupingBy(Sample::getSampleTypeId,
Collectors.collectingAndThen(
Collectors.groupingBy(Sample::getSampleType,
Collectors.summingInt(Sample::getSampleQuantity)),
map -> map.getOrDefault(SampleType.ADD, 0)
- map.getOrDefault(SampleType.SUBTRACT, 0))))
.entrySet()
.stream()
.map(entry->new SummaryResult(entry.getKey()),entry.getValue())
.collect(Collectors.toList());
答案 2 :(得分:0)
ToIntFunction<Sample> signedQuantityMapper= sample -> sample.getQuantity()
* (sample.getType() == Type.ADD ? 1 : -1);
Function<Sample, String> keyMapper = s -> Integer.toString(s.getTypeId());
Map<String, Integer> result = sampleList.stream().collect(
Collectors.groupingBy(
keyMapper,
Collectors.summingInt(signedQuantityMapper)));