将hashmap拆分为java 8中的分区

我有hashmap: Map<String, Set> myMap

我想将它拆分为包含Map列表:

 List<Map<String,Set>> listofMaps; 

,每张地图最多100个键。 我知道如何以常规的方式做到这一点..(关于入口集的foreach,每100个项目创建新的地图)。 有没有选择用java 8 lambda做什么? (像Lists.partitions() ..)?

使用我的unorderedBatches()收集器来回答:

 Collector>, ?, List>>> batchesCollector = unorderedBatches(100, Collectors.toMap(Entry::getKey, Entry::getValue), Collectors.toList()); List>> listofMaps = myMap.entrySet().stream() .collect(batchesCollector); 

将流拆分为有序的固定大小的块(如在Lists.partition )是不可能的,因为在并行执行中,每个块必须等待其左空间块被完全处理。

但是,如果您不关心生成的子映射中的键的顺序(因为它将由Map#iterator的方法返回),那么您可以滚动自定义收集器。

 private static  Collector, ?, List>> mapSize(int limit) { return Collector.of(ArrayList::new, (l, e) -> { if (l.isEmpty() || l.get(l.size() - 1).size() == limit) { l.add(new HashMap<>()); } l.get(l.size() - 1).put(e.getKey(), e.getValue()); }, (l1, l2) -> { if (l1.isEmpty()) { return l2; } if (l2.isEmpty()) { return l1; } if (l1.get(l1.size() - 1).size() < limit) { Map map = l1.get(l1.size() - 1); ListIterator> mapsIte = l2.listIterator(l2.size()); while (mapsIte.hasPrevious() && map.size() < limit) { Iterator> ite = mapsIte.previous().entrySet().iterator(); while (ite.hasNext() && map.size() < limit) { Map.Entry entry = ite.next(); map.put(entry.getKey(), entry.getValue()); ite.remove(); } if (!ite.hasNext()) { mapsIte.remove(); } } } l1.addAll(l2); return l1; } ); } 

这个将地图条目作为值并将它们放入List>

累加器,检查当前列表是否为空或者最后一个映射的大小是否达到限制。 如果是这种情况,则添加新地图。 然后,将处理的当前条目的新映射添加到地图中。

组合器需要组合两个并行构建的列表。 如果其中一个列表为空,则返回另一个。 如果不是这种情况,则需要检查第一个列表的最后一个映射是否具有所需的元素数。 如果不是这种情况,我们抓住第二个列表的最后一个地图,我们将元素添加到第一个列表的最后一个地图。 如果达到限制或者没有更多元素要从第二个列表添加,它将停止。 如果已经消耗了所有元素,请不要忘记删除空地图。

这种收集器的一种用法是:

 List>> listofMaps = myMap.entrySet().stream().collect(mapSize(2)); 

一些示例(包含并行和顺序流),初始映射由13个键值映射组成:

 Size of maps 2 {11=[11a, 11b], 12=[12a, 12b]} {13=[13b, 13a], 8=[8a, 8b]} {1=[1a, 1b], 2=[2b, 2a]} {3=[3a, 3b], 6=[6a, 6b]} {4=[4a, 4b], 5=[5a, 5b]} {7=[7a, 7b], 10=[10a, 10b]} {9=[9a, 9b]} ============================= Size of maps 5 {11=[11a, 11b], 12=[12a, 12b], 13=[13b, 13a], 6=[6a, 6b], 7=[7a, 7b]} {1=[1a, 1b], 2=[2b, 2a], 3=[3a, 3b], 4=[4a, 4b], 5=[5a, 5b]} {8=[8a, 8b], 9=[9a, 9b], 10=[10a, 10b]} ============================= Size of maps 12 {11=[11a, 11b], 12=[12a, 12b], 1=[1a, 1b], 13=[13b, 13a], 2=[2b, 2a], 3=[3a, 3b], 4=[4a, 4b], 5=[5a, 5b], 6=[6a, 6b], 7=[7a, 7b], 8=[8a, 8b], 9=[9a, 9b]} {10=[10a, 10b]} ============================= Size of maps 15 {11=[11a, 11b], 12=[12a, 12b], 13=[13b, 13a], 1=[1a, 1b], 2=[2b, 2a], 3=[3a, 3b], 4=[4a, 4b], 5=[5a, 5b], 6=[6a, 6b], 7=[7a, 7b], 8=[8a, 8b], 9=[9a, 9b], 10=[10a, 10b]} 

我没有对它进行过广泛的测试。 另外我认为你可以修改它以使它更通用。

例如,您可以接受任意对象,并使用两个函数为您正在处理的每个实例生成一个键和一个值。

 private static  Collector>> mapSize(Function keyFunc, Function mapFunc, int limit) { 

 l.get(l.size() - 1).put(keyFunc.apply(e), mapFunc.apply(e)); 

并称之为:

 .collect(mapSize(Map.Entry::getKey, Map.Entry::getValue, size));