组,收集器,映射(Int到String),映射(映射到对象)

这是我之前在Group上的问题的延续,Sum byType然后使用Java流获得差异 。

正如所建议的那样,我应该发布一个单独的线程而不是更新原始线程。

因此,在我之前的一系列问题中,我已经实现了这一点,现在,继续进行。

背景:

我有以下数据集

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获取所需输出以进行分组的已接受答案:

 {1=15, 2=10} 

有了这个,我想知道,如果这可以扩展到更多的东西。

首先,我怎么能让它作为Map而不是原始的Map 。 基本上,对于SampleTypeId; 1指HELLO,2指WORLD。

所以我需要一个.map (或者其他函数)来通过调用一个函数say convertType(sampleTypeId)来将数据从1转换为HELLO,将2转换为WORLD。 因此预期的输出将是{"HELLO"=15, "WORLD"=10} 。 是对的吗? 我该如何编辑当前建议的解决方案呢?

最后,我想知道是否也可以将其返回到Object而不是Map 。 所以我想说我有一个对象; SummaryResult with (String) name and (int) result 。 因此它返回List而不是原始Map 。 如何使用.map (或其他)function执行此操作? 或者还有其他方法吗? 预期的产出将是这条线上的东西。

 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"; } 

对于第一部分,考虑到你有某个方法

 String convertType(int typeId) 

您只需要更改第一个分类器

 groupingBy(SampleType::getTypeId) 

对此

 groupingBy(sample -> convertType(sample.getTypeId())) 

其他一切都保持不变。

后期类型有点棘手,技术上并没有从它作为流相关的解决方案中受益。

你需要的是这个:

 public List toSummaryResultList(Map resultMap) { List list = new ArrayList<>(resultMap.size()); for (Map.Entry 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 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调用是“重”(例如,使用数据库或IO),那么最好将其作为一部分调用toSummaryResultList转换,不作为流元素分类器。 在这种情况下,您将从Map类型的Map收集,并在循环内使用convertType 。 我不会考虑添加任何代码,因为我认为这个变化是微不足道的。

你确实可以使用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()); 
 ToIntFunction signedQuantityMapper= sample -> sample.getQuantity() * (sample.getType() == Type.ADD ? 1 : -1); Function keyMapper = s -> Integer.toString(s.getTypeId()); Map result = sampleList.stream().collect( Collectors.groupingBy( keyMapper, Collectors.summingInt(signedQuantityMapper)));