【问题标题】:Finding all keys in a HashMap with a character an replace it用一个字符查找 HashMap 中的所有键并替换它
【发布时间】:2011-04-20 17:18:30
【问题描述】:

我有一个 HashMap,现在我需要找到 HashMap 中包含特定 letter 的所有键,并将其替换为另一个 letter

【问题讨论】:

  • 碰撞的可能性是这个问题不可避免的一部分,当它发生时OP需要指定他想要发生的事情。代码应该抛出异常吗?它应该默默地丢失其中一个条目吗?还有什么?
  • 为什么要这样做?这不是 HashMap 特别擅长的操作;您可能可以使用完全不同的解决方案。

标签: java key hashmap


【解决方案1】:

你可以试试这个:

public void replaceKeysChar(char originalChar, char newChar, Map<String, ?> map) {
    Map<String, Object> tempMap = new HashMap<String, Object>();
    for (Map.Entry<String, ?> entry : map.entrySet()) {
        String key = entry.getKey();
        if(key != null){
            key = key.replace(originalChar, newChar);
        }
        tempMap.put(key, entry.getValue());
    }
    map.clear();
    map.putAll(tempMap);
}

这样您只处理 char,而不会更改实现。 另外,当您迭代时,您不会在地图中添加项目(这将是一个坏主意)。

如果您不关心实现,只需返回 tempMap 并删除 clear/putAll 部分(它会消耗更少的资源)。

编辑:

在@locka 的answer 之后,我想我应该指定这个方法不能处理冲突。

如果您的 Map 包含键“toto”和“tata”,并且您执行 `replaceKeysChar('a','o', map) 仅在“toto”值和“tata”之间的值之一s 值将在地图中,另一个将被忽略。

编辑之二:

要处理异常冲突 (à la @Stephen C),只需用这个替换旧的 for

    for (Map.Entry<String, ?> entry : map.entrySet()) {
        String key = entry.getKey();
        if(key != null){
            key = key.replace(originalChar, newChar);
        }
        if(tempMap.containsKey(key))
            throw new CollisionException();
        tempMap.put(key, entry.getValue());
    }

【讨论】:

  • 你能用上面的方法举一个小例子吗,对我有很大帮助
  • @John replaceKeysChar('k', 'j', yourMap);我不明白我怎么能更明确
  • 感谢您告诉我。现在我可以想,这就是你的答案,所以被删除了
【解决方案2】:

这是一个通过抛出异常来“处理”冲突的解决方案。

public void replaceKeysChar(char originalChar, char newChar, Map<String, ?> map) {
    Map<String, Object> tempMap = new HashMap<String, Object>();
    Set<String> tempSet = new HashSet<String>();
    for (Map.Entry<String, ?> entry : map.entrySet()) {
        String originalKey = entry.getKey();
        String newKey = originalKey .replace(originalChar, newChar);
        if (!newKey.equals(originalKey)) {
            if (map.containsKey(newKey) || tempMap.containsKey(newKey)) {
                throw new CollisionException(newKey);
            }
            tempMap.put(newKey, entry.getValue());
            tempSet.add(originalKey());
        }
    }
    map.keySet().removeAll(tempSet);
    map.putAll(tempMap);
}

编辑

修复了以前版本中的错误。

【讨论】:

  • @John replaceKeysChar('k', 'j', yourMap);
  • @Stephen C,此方法不会删除旧密钥(替换之前),map.clear()(删除旧密钥)也会删除未更改的密钥。跨度>
  • @Colin - 我在你之前发现了它:-P。现已修复。
  • @Stephen C,我发现这种方法有点“重”,还有额外的Set。另外它不会处理null 值(也不会处理null 键[我刚刚修复了那个])
  • @Colin - 它更复杂,但假设您只重命名一小部分条目,它应该会显着提高效率。修复了空值情况。 null key case 是不可能的。
【解决方案3】:
  1. 构造一个新的hashmap
  2. 复制所有 旧的(键,值)对 hashmap,除了你替换 OLDCHAR 和 NEWCHAR 在键中
  3. 交换 哈希图结束。

【讨论】:

  • 此解决方案比就地更新哈希图的解决方案更可取。它可能更快;更容易验证正确性;并且更灵活地使用(在您想要保留旧哈希图的情况下)。
【解决方案4】:

所以您想更改密钥。如果 Hashalgorithm 不是什么奇怪的东西,您必须获取所有键值对,从 hashmap 中删除它们,更改它们并重新插入它们。或者将它们插入到新的 Hashmap 中。

【讨论】:

    【解决方案5】:

    我认为人们担心由于不可变性和字符串的哈希码与字符串的值相关联,您无法就地更改字符串键。添加/删除键可能会起作用,但您会冒着发生冲突的风险,最终会意外替换现有字符串。

    解决此问题最明显的方法是使用自定义键,例如

    public class MyKey {
      static private Random r = new Random();
    
      private String keyValue; 
      private final int hashCode = r.nextInt();
    
      @Override
      public int hashCode() {
        return hashCode;
      }
    
      public void setKeyValue(String keyValue) {
        this.keyValue = keyValue;
      }
    
      public String getKeyValue() {
        return keyValue;
      }
    }
    

    此键有一个字符串键值,您可以轻松设置/获取它和一个哈希码,它只是一个随机数。将此键添加到哈希映射后,您可以在原位更改字符串,而无需添加或删除该键。您需要做的就是迭代密钥集并在密钥上执行您喜欢的任何处理,所有这些都不会影响哈希码或运行冲突或其他任何风险。

    【讨论】:

    • +1 我忽略了碰撞部分(假设 OP 知道它会做什么)但你指定它是对的。
    • 我不确定这个策略是否方便。您需要始终保留对每个特定 MyKey 实例的引用,因为无法恢复 hashCode。但是,如果您必须跟踪 MyKey,为什么不首先跟踪值?
    • Barthelemy,我看到的问题是,键是对哈希图中数据的唯一引用。如果您更改键(例如通过将一个字符串更改为另一个),那么您将面临碰撞和其他不愉快的风险。因此,密钥应该是唯一的,但可以访问有效负载。哈希码只是哈希图的提示。严格来说,它应该尽可能唯一,但它只是在算法选择将密钥插入哪个存储桶时使用。它通常与 equals() 结合使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-26
    • 2019-01-16
    • 2013-03-25
    • 2012-02-07
    • 2017-04-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多