组,收集器,映射(Int到String),映射(映射到对象) [英] Group, Collectors, Map (Int to String), Map (Map to Object)

查看:149
本文介绍了组,收集器,映射(Int到String),映射(映射到对象)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我在 Group,Sum byType上的上一个问题的延续然后使用Java流获取差异

根据建议,我应该发布一个单独的线程而不是更新原始线程。

As suggested, I should post as a separate thread instead of updating the original one.

所以在我之前的一组问题中,我已经实现了这一点,现在,继续。

So with my previous set of question, I have achieved that, and now, with the continuation.

背景:

我有以下数据集

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}

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

With that, I was wondering, if this could be expanded into something more.

首先,我怎么能让它作为 Map< String,Integer> 而不是原来的 Map< Long,Integer>返回。基本上,对于SampleTypeId; 1指的是HELLO,2指的是WORLD。

First, how could I have it return as a Map<String, Integer> instead of the original Map<Long, Integer>. Basically, for the SampleTypeId; 1 refers to HELLO, 2 refers to WORLD.

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

So I would need like a .map (or maybe other function) to transform the data from 1 to HELLO and 2 to WORLD by calling a function say convertType(sampleTypeId)?. So the expected output would then be {"HELLO"=15, "WORLD"=10}. Is that right? How should I edit the current suggested solution to this?

最后,我想知道是否也可以将它返回到Object而不是地图。所以我想说我有一个对象; SummaryResult with(String)name和(int)result 。因此它返回列表< SummaryResult> 而不是原始的 Map< Long,Integer> 。如何使用 .map (或其他)功能执行此操作?或者还有其他方法吗?预期的输出将是这一行。

Lastly, I would like to know if it is also possible to return it to a Object instead of a Map. So let's say I have a Object; SummaryResult with (String) name and (int) result. So it returns a List<SummaryResult> instead of the original Map<Long, Integer>. How can I use the .map (or other) feature to do this? Or is there other way to doing so? The expected output would be something along this line.

SummaryResult(name="hello", result=15), 
SummaryResult(name="world", result=10), 

非常感谢它的解释以前由@M给出的步骤。 Prokhorov。

Would really appreciate it with the explanation in steps as given previously by @M. Prokhorov.

更新:

更新到

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


推荐答案

第一部分,考虑到你方法

For first part, considering you have somewhere the method

String convertType(int typeId)

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

You simply need to change first classifier from this

groupingBy(SampleType::getTypeId)

到此

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

其他一切都保持不变。

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

Latter type is a little trickier, and technically doesn't benefit from it being a stream-related solution at all.

您需要的是:

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

您可以将此作为收藏家构成的一部分,您的整个收藏家将获得包装成 collectAndThen 致电:

You can use this as part of collector composition, where your whole collector will get wrapped into a collectingAndThen call:

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

然而,正如你所看到的那样,整个收藏家都被包裹起来,所以我眼中对上面没有任何实际好处版本更简单,更容易遵循(至少对我来说)版本使用中间变量,但不是一个代码墙:

However, as you can see, it is the whole collector that gets wrapped, so there is no real benefit in my eyes to the above version to a simpler and easier to follow (at least to me) version below that uses an intermediate variable, but isn't so much of a wall of code:

// 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 调用是重(例如,使用数据库或IO),然后最好将其作为 toSummaryResultList 转换的一部分进行调用,而不是作为流元素分类器。在这种情况下,您将从 Map< Integer,Integer> 类型的地图中收集,并使用 convertType 环。我不会考虑添加任何代码,因为我认为这个变化是微不足道的。

Another point to consider in above is: convertType method will be called as many times as there are elements in sampleList, so if convertType call is "heavy" (for example, uses database or IO), then it's better to call it as part of toSummaryResultList conversion, not as stream element classifier. In which case you will be collecting from map of type Map<Integer, Integer> still, and using convertType inside the loop. I will not add any code with this in consideration, as I view this change as trivial.

这篇关于组,收集器,映射(Int到String),映射(映射到对象)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆