繁体   English   中英

小写所有 HashMap 键

[英]Lowercase all HashMap keys

我遇到了一个场景,我想小写 HashMap 的所有键(不要问为什么,我只需要这样做)。 HashMap 有数百万个条目。

起初,我以为我只是创建一个新 Map,遍历要小写的地图条目,然后添加相应的值。 这个任务应该每天只运行一次或类似的东西,所以我想我可以忍受这个。

Map<String, Long> lowerCaseMap = new HashMap<>(myMap.size());
for (Map.Entry<String, Long> entry : myMap.entrySet()) {
   lowerCaseMap.put(entry.getKey().toLowerCase(), entry.getValue());
}

然而,这导致了一些 OutOfMemory 错误,因为在我即将复制 Map 的这段时间内我的服务器过载。

现在我的问题是,如何以最小的内存占用完成这项任务?

会在小写后删除每个键 - 添加到新的 Map 帮助中吗?

我可以利用 java8 流来加快速度吗? (例如这样的东西)

Map<String, Long> lowerCaseMap = myMap.entrySet().parallelStream().collect(Collectors.toMap(entry -> entry.getKey().toLowerCase(), Map.Entry::getValue));

更新它似乎是一个Collections.unmodifiableMap所以我没有选择

小写后删除每个键 - 添加到新地图

您可以尝试使用不区分大小写排序的TreeMap ,而不是使用HashMap 这将避免需要为每个键创建小写版本:

Map<String, Long> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
map.putAll(myMap);

一旦你构建了这个映射, put()get()将不区分大小写,所以你可以使用全小写的键来保存和获取值。 迭代键将以其原始的,可能是大写形式返回它们。

下面是一些类似的问题:

迭代地图时不能删除条目。 如果您尝试这样做,您将遇到 ConcurentModificationException。

由于问题是 OutOfMemoryError,而不是性能错误,因此使用并行流也无济于事。

尽管最近将完成有关 Stream API 的一些任务,但这仍然会导致在某个时候内存中有两个映射,因此您仍然会遇到问题。

为了解决这个问题,我只看到了两种方法:

  • 为您的进程提供更多内存(通过在 Java 命令行上增加 -Xmx)。 这些天内存很便宜;)
  • 拆分地图并分块工作:例如,您将地图的大小除以 10,一次处理一个块,并在处理新块之前删除已处理的条目。 通过这样,而不是内存中地图的两倍,您将只有地图的 1.1 倍。

对于拆分算法,您可以使用 Stream API 尝试这样的操作:

Map<String, String> toMap = new HashMap<>();            
int chunk = fromMap.size() / 10;
for(int i = 1; i<= 10; i++){
    //process the chunk
    List<Entry<String, String>> subEntries = fromMap.entrySet().stream().limit(chunk)
        .collect(Collectors.toList());  

    for(Entry<String, String> entry : subEntries){
        toMap.put(entry.getKey().toLowerCase(), entry.getValue());
        fromMap.remove(entry.getKey());
    }
}

上述答案中的问题是正确的,您可能需要重新考虑更改您正在使用的数据结构。

对我来说,我有一个简单的地图,我需要将其键更改为小写

看看我的代码片段,它是一个微不足道的解决方案,而且性能很差

private void convertAllFilterKeysToLowerCase() {
    HashSet keysToRemove = new HashSet();
    getFilters().keySet().forEach(o -> {
        if(!o.equals(((String) o).toLowerCase()))
            keysToRemove.add(o);
    });
    keysToRemove.forEach(o -> getFilters().put(((String) o).toLowerCase(), getFilters().remove(o)));
}

不确定内存占用。 如果使用 Kotlin,您可以尝试以下操作。

val lowerCaseMap = myMap.mapKeys { it.key.toLowerCase() }

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/map-keys.html

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM