当前位置: 首页 > 知识库问答 >
问题:

在java 8中将哈希映射拆分为分区[重复]

谈琦
2023-03-14

我有hashmap:Map

我想把它分成包含< code>Map的列表:

List<Map<String,Set<String>>> listofMaps;

,每个地图最多 100 个键。我知道如何以常规方式做到这一点。(在条目集上,每 100 个项目创建新地图)。有没有选择使用 java 8 lambda 或其他东西来做到这一点?(类似于 Lists.partitions() ..)?

共有2个答案

段宏毅
2023-03-14

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

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

private static <K, V> Collector<Map.Entry<K, V>, ?, List<Map<K, V>>> 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<K, V> map = l1.get(l1.size() - 1);
                    ListIterator<Map<K, V>> mapsIte = l2.listIterator(l2.size());
                    while (mapsIte.hasPrevious() && map.size() < limit) {
                        Iterator<Map.Entry<K, V>> ite = mapsIte.previous().entrySet().iterator();
                        while (ite.hasNext() && map.size() < limit) {
                            Map.Entry<K, V> entry = ite.next();
                            map.put(entry.getKey(), entry.getValue());
                            ite.remove();
                        }
                        if (!ite.hasNext()) {
                            mapsIte.remove();
                        }
                    }
                }
                l1.addAll(l2);
                return l1;
            }
    );
}

这个将地图条目作为值并将它们放入列表中

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

合并器需要合并两个并行构建的列表。如果其中一个列表为空,则返回另一个。如果不是这样,您需要检查第一个列表的最后一个映射是否具有所需的元素数量。如果不是这样,我们获取第二个列表的最后一个映射,并向第一个列表的最后一个映射添加元素。如果达到了限制或者第二个列表中没有更多元素要添加,它就会停止。如果空地图的所有元素都被消耗掉了,不要忘记移除它。

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

List<Map<String, Set<String>>> 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 <T, K, V> Collector<T, ?, List<Map<K, V>>> mapSize(Function<T, K> keyFunc, Function<T, V> mapFunc, int limit) {

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

并称之为:

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

印辉
2023-03-14

使用我的unorderedBatch()收集器从这个答案:

Collector<Entry<String, Set<String>>, ?, List<Map<String, Set<String>>>> batchesCollector = 
    unorderedBatches(100, 
        Collectors.toMap(Entry::getKey, Entry::getValue), Collectors.toList());
List<Map<String, Set<String>>> listofMaps = myMap.entrySet().stream()
        .collect(batchesCollector);
 类似资料:
  • 本文向大家介绍Java中并发哈希映射和同步哈希映射之间的区别,包括了Java中并发哈希映射和同步哈希映射之间的区别的使用技巧和注意事项,需要的朋友参考一下 并发Hashmap是jdk1.5中引入的类。并发哈希映射仅在添加或更新映射时在称为片段的存储桶级别应用锁。因此,并发哈希映射允许对映射进行并发读写操作。  同步hashmap(Collection.syncronizedHashMap())是C

  • 我正在尝试创建一个函数,该函数通过二叉树搜索重复节点并将每个唯一节点在树中出现的次数存储到哈希图中。 这是一个更具体的问题- “创建一个名为YourBinaryTree的公共类,该类扩展BinaryTree。重写受保护的映射。” 我尝试递归地搜索树,但似乎无法使其工作,因为重复节点正在创建新映射,而不是替换旧映射的值。 以下是我迄今为止编写的代码: 以下是创建二叉树的类的代码: 我尝试过使用mer

  • 我需要从我的Android向Algolia发送数据,发送的数据应该是JSONObject格式(导入org.json.JSONObject) Algolia中的数据应采用此格式 所以在Android中,我这样设置代码 在这行代码中 那么我应该怎么做才能以JSONObject格式发送hashmap数据呢?

  • 我想获取一个Javascript对象并将其转换为哈希数组。 以下操作仅获取对象的一个元素并将其转换为数组: 返回: 但是,当我试图创建散列元素来组成数组时,出现了一个错误: 返回: 我做错了什么?

  • 我正试图让我的头脑围绕着一个哈姆特的细节。我会用Java自己实现一个,只是为了理解。我熟悉尝试,我想我得到了HAMT的主要概念。 基本上, 两种类型的节点: null null 我不太明白的部分是碰撞检测和缓解。在链接的论文中,他暗示了这一点: 然后将现有键插入到新的子哈希表中,并添加新键。每使用5个以上的散列比特,冲突的概率就减少1/32倍。偶尔,可能会消耗整个32位哈希,必须计算一个新的哈希来

  • > 阅读算法书,需要掌握哈希表的概念。他们写了关于使用单独链接的散列和使用线性探测的散列。我猜Java的HashMap是一个哈希表,因此我想知道HashMaps使用什么机制(链接或探测)? 我需要实现最简单的HashMap与get,put,删除。你能给我指出好的材料来阅读吗? 当用于映射的惟一键是自定义对象时,我们需要在相应的类型中实现hashCode()函数。我做得对吗?或者什么时候需要hash