Reputation: 440
I have a list of objects which I want to aggregate one of the values of this object grouped by other values of the objects in this list.
I'm currently using the properties I want to group by as a Hash key and I'm traversing the object so:
ArrayList<MyObject> raw = Some Data;
Map<String, MyObject> map = new HashMap<String, MyObject>();
for (MyObject ungrouped : raw) {
String key = ungrouped.getStringOne().getName() + ungrouped.getStringTwo() + ungrouped.getStringThree();
if (map.containsKey(key)){
MyObject holder = map.get(key);
holder.setNumericProp(holder.getNumericProp() + ungrouped.getNumericProp());
// map.put(key, holder); //Edited after comments
}
else{
map.put(key, ungrouped);
}
}
return map.values().toArray(new MyObject[map.values().size()]);
Is there a more elegant way to do this without using the concatenated strings as a key?
If this was SQL (from which I'm several application layers away) it would be:
SELECT SUM(numericvalue) FROM sometable GROUP BY stringone, stringtwo , stringthree
Upvotes: 0
Views: 1813
Reputation: 121780
Apart from some problems I see with the code, one solution would be to use (if you can afford it) Guava's Equivalence
(or replicate it in your code). You'd implement an Equivalence<MyObject>
and use a Map<Equivalence.Wrapper<MyObject>, MyObject>
as a container; you'd make the equivalence on your three string members.
That would allow it not to break in this situation:
// Oops! Same key...
s1 = "foo", s2 = "bar", s3 = "baz"
s1 = "fooba", s2 = "rb", s3 = "az"
Also, you could use the return value of the map's .put()
method (the old value):
MyObject holder = map.put(key, ungrouped);
if (holder != null)
holder.setNumericProp(etc);
Upvotes: 2
Reputation: 2467
If your looking elegantly solve this you can use lambdja libraries (Download Here, Website). For example you can SUM a column with the following code (look at this link):
double sum = sumFrom(select(sales,
having(on(Sale.class).getBuyer().isMale())
.and( having(on(Sale.class).getSeller().isMale())))).getCost();
You also can group with this (look at this link):
Group<Person> group = group(meAndMyFriends, by(on(Person.class).getAge()));
With this libraries you can solve your problem in few lines.
Upvotes: 0