这里有一个建议:
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 是分组的秒数:3600 = 小时,900 = 15 分钟
映射中的键当然可以是相当大的数字(取决于采样周期),但是这种分组将保留组的内部时间顺序,即较低的键是时间顺序中最先出现的那些。如果我们假设原始列表中的数据是按时间顺序排列的,我们当然可以得到第一个键的值,然后从键中减去它。这样我们将获得键 0、1 等。在这种情况下,在 for 循环开始之前,我们需要:
整数减法 = items.get(0).timestamp / sample_period; // 注意,因为两个数字都是整数/长整数,所以我们有一个整数除法
然后在for循环内:
group_key = items.timestamp / sample_period - 减去;
这些方面的东西会起作用,即按照您的描述对您的数据集进行分组。然后您可以将 min max avg 等应用于结果列表。但是由于这些函数当然必须再次遍历各个组列表,因此将这些计算合并到这个解决方案中可能会更好,并让函数返回类似 Map 的东西,其中 Aggregates 是一种包含 avg、min、max 字段的新类型,然后是组中的项目列表?至于性能,我认为这是可以接受的。这是一个简单的 O(N) 解决方案。编辑:
好的,只是想添加一个更完整的解决方案/建议,它还计算最小值、最大值和平均值:
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;
}
这只是一个粗略的解决方案。我们可能想向聚合等添加更多属性。