As Ironluca points out in the comments, you are using the wrong tool for the job. The correct solution would be to use Java streams; even a simple for-loop would solve your problem.
Of course, since you can use a hammer on a screw, you can do this with Drools. I will include an example rule and an explanation, though it will be much less efficient than a stream-based solution (or even a for-loop.)
I will assume this model, with appropriate getters, setters, and an all-args constructor:
class Account {
String name;
int quantity;
}
Then this rule will populate an 'output' list with the "grouped" accounts. I've declared this 'output' list as a global, which isn't best-practice but none of this is recommended anyway since it's not the appropriate tool for the job.
global List $output;
rule "Consolidate duplicates"
when
$inputs: List()
Account( $name: name ) from $inputs
$duplicates: List()
from collect( Account( name == $name ) from $inputs )
$total: Number()
from accumulate( Account( $value: quantity ) from $duplicates, sum( $value ) )
then
$output.add(new Account($name, $total));
end
The first part of the rule identifies the subset of Account instances in the input list which share the same name. I use collect
because this is a simple subset of the original input. The next step is to use accumulate
to sum up the quantities from those duplicates. Then we add a new instances to the output list on the rule's RHS with the consolidated quantity and the shared name. Note that the rule works the same for Accounts which have unique names; there is no constraint on length for $duplicates
, and the accumulation would just be the one identified quantity.
Modifying $inputs
in-place is also do-able, but tricky, since you have to worry about concurrent modification exceptions. The much cleaner implementation is to use
Of course this is way more complicated than it has to be. Java 8 streams provide a groupingBy
collector which allows you to trivially create a map by a property within the object:
Map<String, List<Account>> accountsByName = accounts.stream()
.collect(groupingBy(Account::getName));
You could then easily transform this by iterating over the valueset.
This other question goes into detail for other 'summation of duplicates in a stream' scenarios: Java 8 stream sum entries for duplicate keys