【问题标题】:How to remove a Key from a HashMap using the Value [duplicate]如何使用值从 HashMap 中删除键 [重复]
【发布时间】:2018-05-08 13:58:53
【问题描述】:

我有一个任务要求我配置一个地图...

Map<Integer,Event> eventList = new HashMap<>();

我必须编写一个具有以下标头的方法...

public String removeEvent(Event eventObj)

我们的想法是传递一个 Event 对象,检查该事件是否已经作为 Map 中的值存在,如果存在,则将其删除并返回一个字符串消息以确认它已被删除。

我遇到的问题是它规定我不能遍历地图以获得解决方案。

我可以使用 containsValue() 方法或覆盖的 equals() 方法来检查对象是否已存在于地图中,但我现在遇到的问题是我不确定如何删除密钥对值那匹配?

任何帮助都会很好,因为我对地图很陌生,并且经常在键和值之间移动。

【问题讨论】:

  • 为什么要返回字符串?
  • 通过。这是任务的规定。但是我不会这样做。
  • 可能是,但我无法迭代解决此问题。我能找到的所有其他线程都涉及迭代
  • 为什么不能迭代?你不能没有
  • @PaulHarper 发布任务的确切措辞。要么你已经抽象出重要信息,要么这个问题是不可能的。

标签: java hashmap


【解决方案1】:

如果不能迭代1Map,则需要另一个Map来表示反向映射;例如

Map<Integer,Event> forwardMap = new HashMap<>();
Map<Event,Integer> reverseMap = new HashMap<>();

....

void remove (Event event) { 
    Integer key = reverseMap.get(event);
    if (key != null) {
        forwardMap.remove(key);
        reverseMap.remove(event);
    }
}

显然,所有修改正向映射的操作都必须对反向映射进行相应的修改。


1 - 我假设 所有 形式的迭代都是不允许的。这包括使用 Java 8+ 流,其中迭代发生在幕后。如果这不是您的意思,请更新您的问题,以明确什么是允许的,什么是不允许的。

【讨论】:

  • 如何在不迭代的情况下填充reverseMap
  • 你没有。您与正向映射并行填充它。请参阅我的答案的最后一句话。
【解决方案2】:

最简单的解决方案是:

eventList.values().remove(eventObj);

但是,这在后台使用了迭代。没有迭代就无法解决这个问题。

【讨论】:

    【解决方案3】:

    解决办法是写两阶段代码:

    1. 收集属于该值的键
    2. 删除这些键 - 假设它们仍然具有相同的值

    在多线程访问的情况下,可能会考虑某种锁定。为了简单起见,我们把这个负担交给了方法的调用者:

    public String removeEvent(Event eventObj) {
        // phase 1: collect the related keys
        List<Integer> keys = eventList.entrySet().stream()
                .filter(entry -> eventObj.equals(entry.getValue()))
                .map(entry -> entry.getKey())
                .collect(Collectors.toList());
    
        // phase 2: remove those keys
        for (Integer key : keys) {
            // this version of reomve double-checks if that key still has that value
            eventList.remove(key, eventObj);
        }
    
        // it would be good to know the criteria of failure - when should we return something else?
        return "Success";
    }
    

    【讨论】:

    • 您不需要循环来删除密钥。你可以写eventList.keySet().removeAll(keys);
    • @SergiyMedvynskyy 是的,这更优雅。但是,它不检查值是否已更改。毕竟这一切都归结为要求:)
    • eventList.entrySet() == 迭代
    【解决方案4】:

    由于您无法进行迭代,因此您应该调用一个在内部为您执行此操作的函数。 Map.replaceAll() 应该可以工作。此方法将遍历每个条目并将其值替换为 BiFunction 参数返回的值。函数的第一个参数是键,第二个是值。它应该返回新值。

    例子:

    map.replaceAll((key, value) -> {
        if ("foo".equals(value)) return null;
        return value;
    }
    

    【讨论】:

    • 更改键以映射为 null 与删除条目不同。 map.keySet().contains(key) 仍将返回 true
    • replaceAll 使用迭代。
    • 那么我想解决方案是使用基本的 bimap。
    猜你喜欢
    • 2019-06-26
    • 1970-01-01
    • 2015-07-08
    • 2013-07-22
    • 2015-12-28
    • 2017-10-08
    • 2011-12-28
    • 2011-08-30
    • 1970-01-01
    相关资源
    最近更新 更多