替换哈希映射中的所有相同值。

huangapple go评论67阅读模式
英文:

Replace all the same values in a hash map at once

问题

让我们假设我有一个像这样的HashMap:

1 -> A
2 -> B
3 -> B
4 -> A
5 -> A
6 -> B

其中1、2、3、4、5、6是键,A、B、C是值。

我想要做的是以单个步骤替换HashMap中所有值为B的值为A(而不必迭代元素2、3和6,并为每个元素设置A的值)。

基本上,我想要删除对象B,并且在任何引用B的地方,将其替换为A。我认为在C/C++中可以使用指针来实现这一点。在Java中该如何做呢?

英文:

Let's say that I have a HashMap that looks like this:

1 -> A

2 -> B

3 -> B

4 -> A

5 -> A

6 -> B

with 1, 2, 3, 4, 5, 6 being the keys and A, B, C being values.

What I would like to do is replace all values of B with the value of A in the HashMap in a single step (without having to iterate through the elements 2, 3, and 6 and putting the value of A for every single one).

Basically, I would like to remove the object B and everywhere where B is referenced, to replace it with A. I think that in C/C++ this can be achieved using pointers. How can I do it in Java?

答案1

得分: 1

你不能这样做,这不是哈希映射的作用或用途。

实际上,在核心库中没有任何数据结构可以做到这一点。

一个简单而又最优的方法是将可变对象用作值。例如:

Map<Integer, StringBuilder> map = new HashMap<>();
StringBuilder a = new StringBuilder("A");
map.put(1, a);
map.put(2, a);
a.clear();
a.append("b");
System.out.println(map);

上述代码将输出"{1: b, 2: b}"。当然,如果你创建两个包含文本'a'的不同的StringBuilder对象,改变一个不会影响另一个。

Guava 提供了双向映射(bimaps),但总体思路是键和值都是唯一的,显然在这里不适用。Guava还提供了多重映射(multimaps),可以将一个键映射到多个值;你可以使用这些构造函数来手动创建一个数据结构,它包括一个 HashMap<K, V> 以及一个 Multimap<V, K>;HashMap与上面的示例相同,Multimap执行相反的操作,将'B'映射到值'2'、'3'和'6',然后你可以使用它来相对高效地编写一个方法,用于执行“将所有值等于此的替换为那”的任务,方法是查找需要在Multimap中替换的键/值对,然后在HashMap中替换这些k/v对,同时更新Multimap。

请注意,这仍然需要多个步骤,其时间复杂度为O(n),其中n是匹配键的数量,并且在没有相当重的synchronized()锁保护的情况下无法在多线程安全的方式下执行大部分集合API。

英文:

You can't, that's just not what hashmaps do or what they are for.

There are no data structures anywhere in the core libraries that can do this, in fact.

An easy, optimal route is to use mutable objects as values. For example:

Map&lt;Integer, StringBuilder&gt; map = new HashMap&lt;&gt;();
StringBuilder a = new StringBuilder(&quot;A&quot;);
map.put(1, a);
map.put(2, a);
a.clear();
a.append(&quot;b&quot;);
System.out.println(map);

The above would end up printing "{1: b, 2: b}". Of course, if you make 2 separate stringbuilder objects, each containing the text 'a', changing one would NOT change the other.

Guava has bimaps, which are 2-directional, but the general idea is that both keys and values are unique and you obviously don't have that here. Guava also has multimaps, which map one key into multiple values; you could use such constructors to handroll something here, too: Have a data structure that consists of both a HashMap&lt;K, V&gt; as well as a Multimap&lt;V, K&gt;; the hashmap is as above, the multimap does the reverse, and maps, in your example, B to the values 2, 3, and 6, which you can then use to somewhat efficiently write a method that will do the job of 'replace all values equal to THIS with THAT', by looking up which key(s) need replacing in the multimap, then replacing those k/v pairs in the map, as well as updating the multimap.

Note that this is still multiple steps, is O(n) where n is the # of matching keys, and cannot be done in a multithread-safe way without rather heavy handy synchronized() locks around most of the API of your collection.

答案2

得分: 0

为什么不只是维护第二个映射,将字符串到整数集合的映射,这样你就可以维护 2 -> B,3 -> B,6 -> B,以及 B -> [2, 3, 6]。

Map<String, Set<Integer>> letterToKeys = new HashMap<>();
英文:

Why not just maintain a second Map with String to Set<Integer> so that you can maintain 2 -> B, 3 -> B, 6 -> B and B -> [2, 3, 6].

Map&lt;String, Set&lt;Integer&gt;&gt; letterToKeys = new HashMap&lt;&gt;();

huangapple
  • 本文由 发表于 2020年8月31日 00:02:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/63659358.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定