当前位置: 首页 > 面试题库 >

分组和求和对象(如带有Java Lambda的SQL中的对象)?

郭思淼
2023-03-14
问题内容

我有一个Foo与这些领域的课程:

id:int /名称;字符串/ targetCost:BigDecimal / actualCost:BigDecimal

我得到了此类对象的数组列表。例如:

new Foo(1, "P1", 300, 400), 
new Foo(2, "P2", 600, 400),
new Foo(3, "P3", 30, 20),
new Foo(3, "P3", 70, 20),
new Foo(1, "P1", 360, 40),
new Foo(4, "P4", 320, 200),
new Foo(4, "P4", 500, 900)

我想通过创建“ targetCost”和“ actualCost”的总和并将“行”分组来转换这些值

new Foo(1, "P1", 660, 440),
new Foo(2, "P2", 600, 400),
new Foo(3, "P3", 100, 40),
new Foo(4, "P4", 820, 1100)

我现在写的是:

data.stream()
       .???
       .collect(Collectors.groupingBy(PlannedProjectPOJO::getId));

我怎样才能做到这一点?


问题答案:

使用Collectors.groupingBy是正确的方法,但不要使用单个参数版本来创建每个组的所有项目列表,而应使用两个arg版本,后者使用另一个参数版本Collector来确定如何汇总每个组的元素。

当您要汇总元素的单个属性或仅计算每个组中元素的数量时,这特别平滑:

数数:

list.stream()
  .collect(Collectors.groupingBy(foo -> foo.id, Collectors.counting()))
  .forEach((id,count)->System.out.println(id+"\t"+count));

总结一个属性:

list.stream()
  .collect(Collectors.groupingBy(foo -> foo.id,
                                    Collectors.summingInt(foo->foo.targetCost)))
  .forEach((id,sumTargetCost)->System.out.println(id+"\t"+sumTargetCost));

在您要聚合多个属性的情况下,指定一种自定义归约操作(如此答案中所建议的那样)是正确的方法,但是,您可以在分组操作期间执行归约操作,因此无需将整个数据收集到Map<…,List>执行还原之前的a :

(我假设您import static java.util.stream.Collectors.*;现在使用…)

list.stream().collect(groupingBy(foo -> foo.id, collectingAndThen(reducing(
  (a,b)-> new Foo(a.id, a.ref, a.targetCost+b.targetCost, a.actualCost+b.actualCost)),
      Optional::get)))

.forEach((id,foo)->System.out.println(foo));
为了完整起见,这里是一个超出您问题范围的问题的解决方案:如果要GROUP BY多个列/属性该怎么办?

跳入程序员头脑的第一件事是用来groupingBy提取流元素的属性并创建/返回新的关键对象。但这要求键属性具有适当的holder类(而Java没有通用的Tuple类)。

但是还有另一种选择。通过使用三参数形式,groupingBy我们可以为实际Map实现指定供应商,该供应商将确定键的相等性。通过使用带有比较器比较多个属性的排序映射,我们无需其他类即可获得所需的行为。我们只需要注意不要使用比较器忽略的关键实例中的属性,因为它们只有任意值:

list.stream().collect(groupingBy(Function.identity(),
  ()->new TreeMap<>(
    // we are effectively grouping by [id, actualCost]
    Comparator.<Foo,Integer>comparing(foo->foo.id).thenComparing(foo->foo.actualCost)
  ), // and aggregating/ summing targetCost
  Collectors.summingInt(foo->foo.targetCost)))
.forEach((group,targetCostSum) ->
    // take the id and actualCost from the group and actualCost from aggregation
    System.out.println(group.id+"\t"+group.actualCost+"\t"+targetCostSum));



 类似资料:
  • 问题内容: 一个人如何处理一个javascript对象数组,例如: 并通过将值相加来合并重复的键。为了得到这样的东西: 我尝试迭代并添加到新数组,但这没有用: 问题答案: 您应该使用属性将未找到的每个对象分配给结果。 如果找到它,则需要添加它。 另外,部分问题是您正在重用变量来引用的值,因此您失去了对该对象的引用。

  • 我是Spring的新手,正在注册一个用户。我确实喜欢这个。 这很好,但这里的问题是,在我的欢迎中,我不需要这个用户对象。jsp页面,那么为什么要使模型对象更重呢。因此,我尝试了不使用ModelAttribute,这也适用于我,如下所示。 所以我只想知道什么是专业 我想将我的查询分类为以下4种类型的request.what如果我不需要在视图中发送数据并且我的请求是任何- 查询字符串即GET中的表单数

  • 问题内容: 我有一个类似于以下对象的数组: 我需要将所有具有相同名称的对象的值相加。(可能还包括其他数学运算,例如计算平均值。)对于上面的示例,结果将是: 问题答案: 首先遍历数组,然后将“名称”推入另一个对象的属性。如果属性存在,则将“值”添加到属性的值,否则将属性初始化为“值”。构建此对象后,请遍历属性并将其推入另一个数组。 这是一些代码: 希望这可以帮助。

  • 如何处理对象的javascript数组,例如: 并通过求和这些值合并重复的键。为了得到这样的东西: 我尝试过迭代并添加到一个新数组中,但这没有起到作用:

  • 问题内容: 一个人如何处理一个javascript对象数组,例如: 并通过将值相加来合并重复的键。为了得到这样的东西: 我尝试迭代并添加到新数组,但这没有用: 问题答案: 您应该使用属性将未找到的每个对象分配给结果。 如果找到它,则需要添加它。 另外,部分问题是您正在重用变量来引用的值,因此您失去了对该对象的引用。

  • 问题内容: 通过多个属性对数组中的元素进行分组最符合我的问题,因为它确实通过数组中的多个键对对象进行了分组。问题是此解决方案无法汇总属性值,然后删除重复项,而是将所有重复项嵌套在二维数组中。 预期行为 我有一个对象数组,必须按和进行分组。 这个数组中的对象被视为重复仅当其和是相同的。如果它们是,我想分别总结它们的和值,然后删除重复项。 因此,在这个例子的结果阵列可以仅含有四种组合:,,, 问题 我