1

I have a list:

List<FaAccount> accounts = someMethod();

this list contains accountid, currency, balance. Now I want to aggregate balance by currency (sum of balance for each currency). I've created new class with currency and balance variables. This, only copies info from FaAccount into FaAccountBalance

List<FaAccountBalance> aggr = new ArrayList<>();
for(FaAccount account : accounts){
            FaAccountBalance ag = new FaAccountBalance();
            ag.setCurrency(account.getCurrency());
            ag.setBalance(account.getBalance());
            aggr.add(ag);
}

How can I put there (into aggr List) one more for loop or some other technique, so that to represent sum of balance for each currency?

2
  • Where do you want to put the loop exactly and what do you want to sum up ? I dont get your question... Commented Aug 1, 2015 at 13:05
  • @Kami, I want to sum up balance, grouped by currency. For instance, in accounts there may be ['USD', 500], ['USD',200]. In aggr, I want ['USD',700]. The question is where and how I can use for loop for this purpose Commented Aug 1, 2015 at 13:07

3 Answers 3

1

Instead of using a different for loop, you can do it in the same for loop using a HashMap

List<FaAccountBalance> aggr = new ArrayList<>();
HashMap<String,Integer> map = new HashMap<>();
for(FaAccount account : accounts){
        String currency = account.getCurrency();
        int balance =account.getBalance();
        FaAccountBalance ag = new FaAccountBalance();
        ag.setCurrency(currency);
        ag.setBalance(balance);
        aggr.add(ag);        
        map.put(currency,map.getOrDefault(currency,0) + balance);
}

After this for loop, you will have aggregated balance for each currency, just print it like:

for(String currency: map.keySet()){
    System.out.println(currency + " : " + map.get(currency));
}

UPDATE If you want a BigDecimal, you can't just add it with +. You have to use add

map.put(currency,map.getOrDefault(currency, BigDecimal.ZERO).add(new BigDecimal(balance)));

If you want to Store it in List, instead of printing the hashmap contents, add them to the list.

List< FaAcountBalance> result  = new LinkedList<>();
for(String currency: map.keySet()){
    result.add(new FaAcountBalance(currency,map.get(currency)));
}
return result;
Sign up to request clarification or add additional context in comments.

9 Comments

Thanks. what about map.put(currency,map.getOrDefault(currency,BigDecimal.ZERO) + balance); what is wrong? i've changed HashMap to BigDecimal, and is it going to return me desired list ?
There is nothing wrong, it just depends on what type you want to use for aggregated balance.
as BigDecimal, it says getOrDefault(Object,BigDecimal) in Map cannot be applied to BifDecimal
@Sher oh you are talking about the syntax error, I updated my answer. You can't use + directly.
Almost done. One last question, how to put what is in Map into List?
|
1

An other option would consist of using Collectors.groupingBy then simply map each Map.Entry into a FaAccountBalance and collect them as list :

final List<FaAccountBalance> accountBalances = 
    accounts
        .stream()
        .collect(Collectors.groupingBy(FaAccount::getCurrency, Collectors.summingInt(FaAccount::getBalance)))
        .entrySet()
        .stream()
        .map(entry -> {
            final FaAccountBalance f = new FaAccountBalance();
            f.setCurrency(entry.getKey());
            f.setBalance(entry.getValue());
            return f;
        }).collect(Collectors.toList());

3 Comments

Java 8 streams are so unreadable and uneasy to use... One reason is Java compiler's terrible inference type, and the other reason is that the API is just not easily discoverable. I did not know about summingInt, which makes your answer helpful. However, I now consider Java streams as a pain unless you just want to perform simple operations. Scala has a much better API.
@Dici Seems like we have divergent opinions here, I've always found the stream API very intuitive and don't find it hard to read at all. In fact, also doing scala, I find the Java API more readable. However, I must say that I find the Scala one more complete.
One thing I don't like is the collect approach. It leads you to have deeply nested expressions if you want to do complex stuff with multiple collectingAndThen. I prefer list.groupBy(...).mapValues(...) over list.collect(groupingBy(...), summingInt(...)). Also, stream() clutters the code, and it's even worse for a Map on which you must first call either entrySet, values, keySet. You have 3 lines of these in your code, which add nothing to the logic. I'm not criticizing your answer, which is ok, but the Java API.
1

First, your design is not ideal, you have some redundancy. Indeed, you are explicitly copying information, this suggests it is not clear for you who should own this data. I would suggest this better approach :

public class FaAccount {
    private final FaAccountBalance balance;
    private final int accountId;
}

public class FaAccountBalance {
    private float amount;
    private Currency currency;
}

The aggregation is then pretty easy :

Map<Currency, Double> aggregation = new HashMap<>();
for (FaAccount account : accounts) {
   FaAccountBalance balance = account.getBalance();
   aggregation.put(balance.getCurrency(), aggregation.getOrDefault(0) + balance.getAmount());
}

Finally,

List<FaAccountBalance> aggregatedBalances = 
    aggregation.entrySet()
               .map(entry -> new FaAccountBalance(entry.getKey(), entry.getValue()))
               .collect(Collectors.toList());

6 Comments

and how to put it into List?
To put what into which list
Why I can't put BigDecimal.ZERO into getOrDefaultBalance? I've changed Double to BigDecimal
You don't give enough details for me to answer. Did you update it everywhere you need ? Do you have an compile error message ?
karthik gave you the answer : you cannot sum BigDecimals with +. I would add that your question was not complete enough for us to give a complete answer. Think about it next time, you could have included a small snippet of each of your classes to show us the data types
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.