Here is one suggestion:
public Map<Long,List<Item>> group_items(List<Item> items,long sample_period) {
Map<Long,List<Item>> grouped_result = new HashMap<Long,List<Item>>();
long group_key;
for (Item item: items) {
group_key = item.timestamp / sample_period;
if (grouped_result.containsKey(group_key)) {
grouped_result.get(group_key).add(item);
}
else {
grouped_result.put(group_key, new ArrayList<Item>());
grouped_result.get(group_key).add(item);
}
}
return grouped_result;
}
sample_period is the number of seconds to group by: 3600 = hour, 900 = 15 mins
The keys in the map can of course be pretty big numbers (depending on the sample period), but this grouping will preserve the internal time order of the groups, i.e. lower keys are those that come first in the time order. If we assume that the data in the original list is ordered in time order we could of course get the value of the first key and then subtract that from the keys. That way we will get keys 0, 1, etc. In that case before the for loop starts we need:
int subtract = items.get(0).timestamp / sample_period; // note since both numbers a ints/longs we have a integer division
Then inside the for loop:
group_key = items.timestamp / sample_period - subtract;
Something along these lines will work, i.e. group your dataset as you describe. Then you can apply min max avg etc to the resulting lists. But since those functions will of course have to iterate over individual group lists again it is maybe better to incorporate those calculations into this solution, and have the function return something like Map where Aggregates is a new type containing fields for avg, min, max, and then a list of the items in the group? As for performance I would think this is acceptable. This is a plain O(N) solution.
Edit:
ok just want to add a more complete solution/suggestion which also calculates the min, max and avg:
public class Aggregate {
public double avg;
public double min;
public double max;
public List<Item> items = new ArrayList<Item>();
public Aggregate(Item item) {
min = item.value;
max = item.value;
avg = item.value;
items.add(item);
}
public void addItem(Item item) {
items.add(item);
if (item.value < this.min) {
this.min = item.value;
}
else if (item.value > this.max) {
this.max = item.value;
}
this.avg = (this.avg * (this.items.size() - 1) + item.value) / this.items.size();
}
}
public Map<Long,Aggregate> group_items(List<Item> items,long sample_period) {
Map<Long,Aggregate> grouped_result = new HashMap<Long,Aggregate>();
long group_key;
long subtract = items.get(0).timestamp / sample_period;
for (Item item: items) {
group_key = items.timestamp / sample_period - subtract;
if (grouped_result.containsKey(group_key)) {
grouped_result.get(group_key).addItem(item);
}
else {
grouped_result.put(group_key, new Aggregate(item));
}
}
return grouped_result;
}
that is just a rough solution. We might want to add some more properties to the aggregate etc.