下面的类:
public class Foo {
private Date date;
private String name;
private Long number;
}
我现在有一个List<Foo>
,我要转换为Map<Date, Map<String,Long>>
(Long
应为的总和numbers
)。是什么让这个艰难的是,我想在内部地图,其中26日被称为“其他”,这概括了具有数量比其他25下一切正好26项。
我想出了下面的代码:
data.stream().collect(Collectors.groupingBy(e -> e.getDate(), Collectors.groupingBy(e -> {
if (/*get current size of inner map*/>= 25) {
return e.getName();
} else {
return "Other";
}
}, Collectors.summingLong(e -> e.getNumber()))));
正如你所看到的,我不知道如何来检查它们已经在内部地图元素的数量。我怎样才能获得内心地图的当前大小或有另一种方式来实现我想要什么?
我的Java 7的代码:
Map<Date, Map<String, Long>> result = new LinkedHashMap<Date, Map<String, Long>>();
for (Foo fr : data) {
if (result.get(fr.getDate()) == null) {
result.put(fr.getDate(), new LinkedHashMap<String, Long>());
}
if (result.get(fr.getDate()) != null) {
if (result.get(fr.getDate()).size() >= 25) {
if (result.get(fr.getDate()).get("Other") == null) {
result.get(fr.getDate()).put("Other", 0l);
}
if (result.get(fr.getDate()).get("Other") != null) {
long numbers= result.get(fr.getDate()).get("Other");
result.get(fr.getDate()).replace("Other", numbers+ fr.getNumbers());
}
} else {
result.get(fr.getDate()).put(fr.getName(), fr.getNumbers());
}
}
}
编辑:
该图应该帮助我实现这样一个表:
但我需要总结的“其他”之首。
如果您需要更多的相关信息随意问
我不认为这个操作会从使用Stream API中获益。不过,你可以改善与Java 8的功能操作:
Map<Date, Map<String, Long>> result = new LinkedHashMap<>();
for(Foo fr : data) {
Map<String, Long> inner
= result.computeIfAbsent(fr.getDate(), date -> new LinkedHashMap<>());
inner.merge(inner.size()>=25?"Other":fr.getAirlineName(), fr.getNumbers(), Long::sum);
}
此代码假定该航空公司的名字已经为每个日期是唯一的。否则,你将不得不代码扩展到
Map<Date, Map<String, Long>> result = new LinkedHashMap<>();
for(Foo fr : data) {
Map<String, Long> inner
= result.computeIfAbsent(fr.getDate(), date -> new LinkedHashMap<>());
inner.merge(inner.size() >= 25 && !inner.containsKey(fr.getAirlineName())?
"Other": fr.getAirlineName(), fr.getNumbers(), Long::sum);
}
正确地积累了航空公司的值。
为了完整起见,这里是如何实现它的流操作。
由于定义采集有一定的复杂性,这是值得书写它作为可重用的代码:
public static <T,K,V> Collector<T,?,Map<K,V>> toMapWithLimit(
Function<? super T, ? extends K> key, Function<? super T, ? extends V> value,
int limit, K fallBack, BinaryOperator<V> merger) {
return Collector.of(LinkedHashMap::new, (map, t) ->
mergeWithLimit(map, key.apply(t), value.apply(t), limit, fallBack, merger),
(map1,map2) -> {
if(map1.isEmpty()) return map2;
if(map1.size()+map2.size() < limit)
map2.forEach((k,v) -> map1.merge(k, v, merger));
else
map2.forEach((k,v) ->
mergeWithLimit(map1, k, v, limit, fallBack, merger));
return map1;
});
}
private static <T,K,V> void mergeWithLimit(Map<K,V> map, K key, V value,
int limit, K fallBack, BinaryOperator<V> merger) {
map.merge(map.size() >= limit && !map.containsKey(key)? fallBack: key, value, merger);
}
这就好比Collectors.toMap
,但支持的限制和其它条目回退键。你可能认识的Map.merge
呼叫,类似环溶液作为关键因素。
然后,你可以使用收集器作为
Map<Date, Map<String, Long>> result = data.stream().collect(
Collectors.groupingBy(Foo::getDate, LinkedHashMap::new,
toMapWithLimit(Foo::getAirlineName, Foo::getNumbers, 25, "Other", Long::sum)));
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句