2013-08-27 3 views
2

У меня есть POJO вроде следующего:Как рефакторировать/агрегировать числовые значения в ArrayList в Java?

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

Используйте HashMap<String,AgentSales> где ключ является агентом + месяц + год агрегировать.

вроде как это:

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>) и распечатать его

+0

Если я использую конкатенированный ключ как агент + месяц + год, как бы обработать его, чтобы вернуть агрегированные значения в ArrayList в том же формате? – fledglingCoder

+0

хороший. +1 .. – jmcg

0

Ваш рисунки кажется ущербной с самого начала , Вы должны были создать класс Agent, который будет содержать личную информацию, а затем AgentSales, которая будет содержать ссылку на агента и значение продаж.

С помощью этих классов можно отсортировать список по Agent и сумма значений в одной итерации для каждой группы AgentSales, которые имеют один и тот же Agent.

Как бы то ни было, я бы предложил написать обычай Comparator и сравнителю и, используя те, сделайте то же самое, что я описал выше.

+0

Дизайн был требованием для получения объектных реляционных сопоставленных значений в аналогичном шаблоне из грязной базы данных. – fledglingCoder

2

Если вы используете Eclipse Collections, вы можете использовать FastList вместо 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 выходит, мы можем заменить функции с лямбды.

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

Примечание: Я коммиттер для коллекций Eclipse.

Смежные вопросы