2

我有一个 POJO,如下所示:

public class AgentSales {
   private String agent;
   private int month;
   private int year;
   private int salesCount;

   public AgentSales(String agent, int month, int year, int salesCount) {
       // initializers ...
   } 

   // getters & setters
   // ...
}

还有一个像下面这样的集合:

ArrayList<AgentSales> salesList = new ArrayList<AgentSales>();

salesList.add(new AgentSales("Ben", 1, 2013, 3));
salesList.add(new AgentSales("Ben", 1, 2013, 2));
salesList.add(new AgentSales("Ben", 2, 2013, 1));
salesList.add(new AgentSales("Ben", 3, 2013, 1));
salesList.add(new AgentSales("Ben", 2, 2013, 2));
salesList.add(new AgentSales("Tim", 1, 2013, 1));
salesList.add(new AgentSales("Tim", 1, 2013, 1));
salesList.add(new AgentSales("Tim", 2, 2013, 1));
salesList.add(new AgentSales("Tim", 4, 2013, 1));
salesList.add(new AgentSales("Tim", 2, 2013, 5));
salesList.add(new AgentSales("Joe", 2, 2013, 1));
salesList.add(new AgentSales("Joe", 2, 2013, 2));
salesList.add(new AgentSales("Joe", 3, 2013, 1));
salesList.add(new AgentSales("Joe", 3, 2013, 2));
salesList.add(new AgentSales("Joe", 3, 2013, 1));

如何重构/聚合此 ArrayList 的内容,以便将对应于同一月份和代理的多个项目合并为 1,并将 salesCount 值相加?

Agent | month | year | sales count
----------------------------------
Ben   |   1   | 2013 |      5
Ben   |   2   | 2013 |      3
Ben   |   3   | 2013 |      1 
Tim   |   1   | 2013 |      2
Tim   |   2   | 2013 |      6
4

3 回答 3

4

使用 aHashMap<String,AgentSales>其中键是 agent+month+year 进行聚合。

有点像这样:

HashMap<String,AgentSales> aggregate = new HashMap<>();
for (AgentSales as : salesList) {
   String key = as.getAgent() + as.getMonth() + as.getYear();
   AgentSales existing = aggregate.get(key);
   if (existing==null) {
      aggregate.put(key,as);
      continue;
   }
   AgentSales combined = new AgentSales(as.getAgent(), as.getMonth(), as.getYear(), as.getSalesCount()+exisgint.getSalesCount());
   aggregate.put(key, combined); 
}

现在您在地图中获得了代理+月+年的组合值。然后,您可以像这样将它们作为 ArrayList 取回:

ArrayList<AgentSales> asList = new ArrayList<>(aggregate.values());

然后您可以对此进行排序(通过编写Comparator<AgentSales>或制作 AgentSales 实现Comparable<AgentSales>)并打印出来

于 2013-08-27T15:11:01.460 回答
2

如果您使用的是Eclipse Collections,则可以使用 aFastList而不是 a ArrayList,然后使用该aggregateBy()方法。这假设您创建了一个 Key 类,它实现了equals()hashCode()

Function<AgentSales, Key> groupBy = new Function<AgentSales, Key>()
{
    public Key valueOf(AgentSales agentSales)
    {
        return new Key(agentSales.agent, agentSales.year, agentSales.month);
    }
};

Function2<Integer, AgentSales, Integer> nonMutatingAggregator =
    new Function2<Integer, AgentSales, Integer>()
{
    public Integer value(Integer sum, AgentSales agentSales)
    {
        return sum + agentSales.salesCount;
    }
};

MutableMap<Key, Integer> aggregate =
    salesList.aggregateBy(groupBy, Functions0.value(0), nonMutatingAggregator);
System.out.println(aggregate.keyValuesView().makeString("\n"));

这会打印出类似的内容:

agent='Ben', month=1, year=2013}:5
agent='Joe', month=2, year=2013}:3
agent='Ben', month=3, year=2013}:1
agent='Ben', month=2, year=2013}:3
agent='Joe', month=3, year=2013}:4
agent='Tim', month=4, year=2013}:1
agent='Tim', month=1, year=2013}:2
agent='Tim', month=2, year=2013}:6

当 Java 8 出来时,我们可以用 lambdas 替换函数。

MutableMap<Key, Integer> aggregate = salesList.aggregateBy(
    agentSales -> new Key(agentSales.agent, agentSales.year, agentSales.month), 
    () -> 0, 
    (sum, agentSales) -> sum + agentSales.salesCount);

注意:我是 Eclipse 集合的提交者。

于 2013-08-28T02:25:10.160 回答
0

你的设计似乎从一开始就有缺陷。您应该创建了一个Agent包含个人信息的类,然后AgentSales将包含对代理的引用和销售价值。

使用这些类,您可以对列表进行排序,Agent并在一次迭代中对AgentSales具有相同Agent.

实际上,我建议编写一个自定义Comparator和相等比较器,并使用它们执行我上面描述的相同操作。

于 2013-08-27T15:15:18.177 回答