从大型集合中遍历和分组相似对象的有效方法

时间:2017-11-27 00:03:23

标签: java data-structures java-8 grouping

我目前正在努力实现一个基本上涉及参与对象的arraylist的实现,例如1000,在他们的属性中找到共性并将它们分组。

例如

ArrayList itemList<CustomJaxbObj> = {Obj1,obj2,....objn} //n can reach to 1000

对象属性 - 注册年份,地点,金额

分组标准 - 对于具有相同年份的reg和location的对象...添加金额

如果有10个对象,其中8个对象具有相同的loc和年份,则为reg和loc年匹配的所有8个和其他2个添加金额。所以在操作结束时,我留下了2个物体。 1是8个匹配对象的总和,1是总共2个匹配的对象标准。

目前我正在使用双传统循环。高级循环更好,但它们不提供对索引的大量控制,我需要执行分组。它允许我跟踪哪些单独的条目组合在一起形成一个新的分组条目条目。

for (i = 0; i < objlist.size(); i++) {
  for(j = i+1; j< objList.size();j++){
    //PErform the check with if/else condition and traverse the whole list
   }
}

虽然这样做了,看起来非常低效并且处理繁重。有一个更好的方法吗。我看到其他答案要求我使用Java8流,但操作很复杂,因此需要进行分组。我已经给出了一个在匹配时做某事的例子,但除此之外还有更多内容。

有更好的方法吗?一个更好的数据结构来保存这种数据,使搜索和分组更容易?

添加更多视角,为之前不提供此信息道歉。

arraylist是来自传入的有效负载xml的jaxb对象的集合。

XML heirarchy

    <Item>
<Item1>
    <Item-Loc/>
    <ItemID>
    <Item-YearofReg/>
    <Item-Details>
        <ItemID/>
        <Item-RefurbishMentDate>
        <ItemRefurbLoc/>
    </Item-Details>
</Item1>
<Item2></Item2>
<Item3></Item3>
....
</Item>

因此项目的Jaxb对象具有900-1000个项目的列表。每个项目可能都有一个具有翻新日期的ItemDetails的子部分。我面临的问题是,当没有项目细节部分时,双循环工作正常,并且每个项目都可以遍历和检查。要求说如果物品已经翻新,那么我们会忽略它的年份,而是考虑翻新年份以符合标准。

另一点是,项目细节不必属于该部分中的同一项目,即Item1项目详细信息可以出现在Item2项目详细信息部分中,项目ID是用于将正确项目映射到的字段其项目详情。

这意味着我无法开始进行更改,除非我已阅读完整列表。一个正常的循环可以做到这一点,但它会增加圈复杂度,由于双循环已经增加了。

因此这个问题需要数据结构在执行分组之前首先存储和分析对象列表。

道歉,之前没有提到这一点。我在stackoverflow中的第一个问题,因此缺乏经验。

2 个答案:

答案 0 :(得分:1)

不是100%确定你的目标是什么,但这里有一些东西可以帮助你入门。要按两个属性进行分组,您可以执行以下操作:

Map<String, Map<Integer, List<MyObjectType>>> map = itemList.stream()
                .collect(Collectors.groupingBy(MyObjectType::getLoc,
                         Collectors.groupingBy(MyObjectType::getYear)));

上面的解决方案假定getLocString类型而getYear是类型Integer,然后您可以执行进一步的流操作以获得所需的总和。< / p>

答案 1 :(得分:0)

您可以将Collectors.groupingBy(classifier, downstream)Collectors.summingInt一起用作下游收集器。你没有发布对象的类,所以我请假定义我自己的。但这个想法很相似。我还使用AbstractMap.SimpleEntry作为最终地图的关键。

import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class GroupByYearAndLoc {
    static class Node {
        private Integer year;
        private String loc;
        private int value;

        Node(final Integer year, final String loc, final int value) {
            this.year = year;
            this.loc = loc;
            this.value = value;
        }
    }

    public static void main(String[] args) {
        List<Node> nodes = new ArrayList<>();
        nodes.add(new Node(2017, "A", 10));
        nodes.add(new Node(2017, "A", 12));
        nodes.add(new Node(2017, "B", 13));
        nodes.add(new Node(2016, "A", 10));

        Map<AbstractMap.SimpleEntry<Integer, String>, Integer> sums = nodes.stream()
                // group by year and location, then sum the value.
                .collect(Collectors.groupingBy(n-> new AbstractMap.SimpleEntry<>(n.year, n.loc), Collectors.summingInt(x->x.value)));
        sums.forEach((k, v)->{
            System.out.printf("(%d, %s) = %d\n", k.getKey(), k.getValue(), v);
        });
    }
}

输出:

(2017, A) = 22
(2016, A) = 10
(2017, B) = 13