对List中的值求和。我可以更有效地做这件事吗?

时间:2014-03-27 19:44:13

标签: java performance list

我有一个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对象列表中?

编辑:

我忘了提到我需要保持项目的顺序

3 个答案:

答案 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;

}