如何使用值从HashMap中删除一个键

3

我有一个任务需要我拥有一个已经配置好的Map...

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

我需要编写一个具有以下标题的方法...

public String removeEvent(Event eventObj)

想法是传递一个事件对象,检查该事件是否已存在于Map中作为值,如果存在,则删除它并返回一个字符串消息,以确认已被删除。
我的问题是,它规定我不能迭代Map来解决问题。
我可以使用containsValue()方法或我的重写equals()方法来检查对象是否已经存在于Map中,但现在我不确定如何删除与之匹配的键值对?
由于我对Maps比较新手,经常在Key和Value之间移动时遇到困难,所以任何帮助都会很好。

可能是这样,但我无法通过迭代来解决这个问题。而且我能找到的所有其他线程都涉及迭代。 - Paul Harper
为什么无法迭代?你不能没有。 - azro
再次尝试。我认为大学提出这样的问题并规定我不能使用迭代器并且必须返回一个字符串,肯定有他们的原因。我相信他们有他们的理由。但是只有上帝知道它们是什么?我只能设法想出一个适合的解决方案。 - Paul Harper
什么是键?它能从相关的值中推导出来吗? - Alan Hay
2
@PaulHarper 发布任务的确切措辞。你可能已经省略了重要信息,或者问题是不可能解决的。 - Michael
显示剩余6条评论
4个回答

2

如果您无法对Map进行迭代,您需要另一个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 - Michael
1
你不需要这样做。你可以与正向映射并行地填充它。请参见我的答案的最后一句话。 - Stephen C

2
最简单的解决方案是:
eventList.values().remove(eventObj);

然而,这背后使用了迭代。如果没有迭代,你无法解决这个问题。

0

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

示例:

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

将键更改为映射到null并不等同于删除条目。map.keySet().contains(key)仍将返回true。 - Michael
replaceAll使用迭代。 - lexicore
那么,我想解决方案就是使用一个基本的双向映射。 - killjoy

0

解决方案是编写两阶段代码:

  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";
}

1
你不需要使用循环来移除键。你可以写成 eventList.keySet().removeAll(keys); - Sergiy Medvynskyy
@SergiyMedvynskyy 是的,那更加优雅。然而,它并没有检查值是否已经改变。毕竟这一切都取决于需求 :) - Tamas Rev
eventList.entrySet() == 迭代 - Michael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接