我有一个Fact对象列表。每个对象都有一个Date字段(reportingDate)和一个long字段(numberSaved)。每个reportingDate有几个结果。我正在尝试获取每个报告日期的所有numberSaved值的总和。目前,我这样做:
private static List<Fact> sumFacts(List<Fact> facts) {
List<Fact> summedFacts = new ArrayList<Fact>();
for (Fact fact : facts) {
boolean found = false;
for (Fact sumFact : summedFacts) {
if(sumFact.getReportingDate().equals(fact.getReportingDate())) {
found = true;
sumFact.setNumberSaved(sumFact.getNumberSaved() + fact.getNumberSaved());
}
}
if (!found) summedFacts.add(fact);
}
return summedFacts;
}
public class Fact {
String reportingDate;
long numberSaved;
public String getReportingDate() {
return reportingDate;
}
public void setReportingDate(String reportingDate) {
this.reportingDate = reportingDate;
}
public long getNumberSaved() {
return numberSaved;
}
public void setNumberSaved(long numberSaved) {
this.numberSaved = numberSaved;
}
}
对于原始列表中的每个项目,它会遍历新列表以查找匹配的日期。如果找到具有匹配日期的对象,则会将其numberSaved值添加到该对象中。如果它在没有找到匹配日期的情况下通过整个列表,它会将自己添加到新列表中。
是否有更有效的方法可以将值汇总到具有唯一日期的Fact对象列表中?
编辑:
我忘了提到我需要保持项目的顺序
答案 0 :(得分:3)
不是将事实保存在List
中并迭代它(产生O(n ^ 2)复杂度),而是可以将它们存储在地图中,作为报告日期到事实对象,给你一个O(n)复杂性:
private static List<Fact> sumFacts(List<Fact> facts) {
Map<String, Fact> summedFacts = new HashMap<Fact>();
for (Fact fact : facts) {
summedFact = summedFacts.get(fact.getReportingDate());
if (summedFact == null) {
summedFacts.put (fact.getReportingDate(), fact);
} else {
summedFact.setNumberSaved(summedFact.getNumberSaved() + fact.getNumberSaved());
}
}
return new ArrayList<Fact>(summedFacts.values());
}
答案 1 :(得分:1)
这可能更快的唯一方法是,如果两个列表都按某个键排序(很可能是您使用的日期)。检查未排序列表中是否存在对象O(n)
,并且您正在为另一个列表的每个元素执行此操作,从而导致问题O(m * n)
。
这表明您的解决方案尽可能高效,无需预先列出清单。
您可以改进的最多是使用List.add(int,Object),以便它将项目插入到列表的前面,以便它不会再次循环。
答案 2 :(得分:1)
您可以通过HashTable
使用summedFacts
来大大提高效果(详情请见http://docs.oracle.com/javase/7/docs/api/java/util/Hashtable.html)
您可以将日期转换为字符串,并将其用作HashTable
的键。 HashTable
的值将保存具有相同日期的Fact
个对象的总和。
HashTable访问是即时的(O(1))因此该解决方案将引导您进行O(n)实现而不是O(n * m)实现。
例如:
private static HashTable<string, Fact> sumFacts(List<Fact> facts) {
HashTable<string, Fact> summedFacts = new Hashtable<string, Fact>();
for (Fact fact : facts) {
// Check if the item with this date is already added to the HashTable. If not, then add it
if (summedFacts.get(sumFact.getReportingDate()) == null)
summedFacts.put(fact.getReportingDate(), fact); // add the value to the HashTable.
else {
// If the date is already there, than perform adition.
currentFact = summedFacts.get(fact.getReportingDate());
currentFact.setNumberSaved(fact.getNumberSaved() + currentFact.getNumberSaved());
}
}
}
return summedFacts;
}