我得到一个Map
对象:
Map<String, Shop>> shopData = GET_SHOP_DATA();
Shop
类包含两个字段:
public class Shop{
private String name;
int salesPerDay
...
}
获得所有商店salesPerDay
的总结的有效方式是什么? (我知道我可以遍历Map对象并进行求和),我的意思是没有循环。
我知道我可以通过Collection
获得shopData.values()
个对象。有没有可能从那里得到总和而没有循环?
答案 0 :(得分:2)
执行此操作的现代方法称为 map-reduce 。它是Java 8的一部分,您只需一行即可完成,但也有框架提供这个。在这里搜索“map reduce”。
W.r.t。 map-reduce你可能会发现这篇文章很有用:Simple Java Map/Reduce framework
Java 8
在Java 8中,解决方案看起来像这样(一行!)
shopData.values().stream().map(s -> s.saledPerDay).sum();
下面
shopData.values()
生成Shop对象的集合stream()
使其成为Shop对象map(s -> s.saledPerDay)
使其成为整数流sum()
总结一下。因为你要求“效率”。可以并行执行此操作(使用多核机器的功能),只需
shopData.values().parallelStream().map(s -> s.saledPerDay).sum();
这是快速而简洁的。
Java 6/7
如果你想在Java 6/7中这样做,那么你可以使用一个库。例如,jedi提供了reduce,以下示例实际上或多或少是您需要的: http://jedi.codehaus.org/javadoc/jedi/functional/FunctionalPrimitives.html#reduce%28java.lang.Iterable,%20jedi.functional.Functor2%29
答案 1 :(得分:1)
您可以包装Map
并将您的额外功能添加到某些方法中。在这里,我定义了SummingMap
,这可能是一个好的开始。我遗漏了许多方法,但他们只需要将调用转发到底层地图。
interface Summable {
public long getValue();
}
public static class Shop implements Summable {
private String name;
private long salesPerDay;
@Override
public long getValue() {
return salesPerDay;
}
}
public static class SummingMap<K, V extends Summable> implements Map<K, V> {
private final Map<K, V> map;
private long sum = 0;
public SummingMap(Map<K, V> map) {
this.map = map;
}
@Override
public V put(K key, V value) {
putting(key, value);
return map.put(key, value);
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
for ( Map.Entry<? extends K, ? extends V> e : m.entrySet() ) {
putting(e.getKey(), e.getValue());
}
map.putAll(m);
}
private void putting(K key, V value) {
if (map.containsKey(key)) {
sum -= map.get(key).getValue();
}
sum += value.getValue();
}
@Override
public V remove(Object key) {
Object o = map.get(key);
if (o != null && o instanceof Summable) {
sum -= ((Summable) o).getValue();
}
return map.remove(key);
}
// Other methods - just forward the call directly to the held map.
}
正如@Christian正确指出的那样,如果您更改salesPerDay
对象中的Store
值而不先将其从地图中删除,则此解决方案将无法保持正确的总和。
您可以通过将每个对象包装在代理中来增强此解决方案,但这又不能提供保证总和。
使salesPerDay
字段最终确定也可能有所帮助,但是在需要总计时,没有任何东西能够保证正确地添加它们。
答案 2 :(得分:0)
首先,您需要获取地图的键集。然后使用迭代器获取商店的每个对象。然后你总是容易添加。试试这个..
Set<String> key = shopData.keySet();
Iterator<String> iterator = key.iterator();
int total;
while(iterator.hasNext()){
Shop shop = shopData.get(iterator.next());
total+= shop.salesPerDay;
}
System.out.println(total);