is there a bidirectional hashmap for kotlin? If not - what is the best way to express this in kotlin? Including guava to get the BiMap from there feels like shooting with a very big gun on a very little target - no solution that I can imagine currently feels right - the best thing I have in mind is to write a custom class for it

推荐答案

I need a simple BiMap implementation too so decided to create a little library called bimap.

BiMap的实现相当简单,但它包含一个棘手的部分,即一组条目、键和值.我将try 解释实现的一些细节,但是您可以在GitHub上找到完整的实现.

首先,我们需要为不可变和可变的BiMap定义接口.

interface BiMap<K : Any, V : Any> : Map<K, V> {
  override val values: Set<V>
  val inverse: BiMap<V, K>
}

interface MutableBiMap<K : Any, V : Any> : BiMap<K, V>, MutableMap<K, V> {
  override val values: MutableSet<V>
  override val inverse: MutableBiMap<V, K>

  fun forcePut(key: K, value: V): V?
}

Please, notice that BiMap.values returns a Set instead of a Collection. Also BiMap.put(K, V) throws an exception when the BiMap already contains a given value. If you want to replace pairs (K1, V1) and (K2, V2) with (K1, V2) you need to call forcePut(K, V). And finally you may get an inverse BiMap to access its keys by values.

BiMap使用两个常规 map 实现:

val direct: MutableMap<K, V>
val reverse: MutableMap<V, K>

The inverse BiMap can be created by just swapping the direct and the reverse maps. My implementation provides an invariant bimap.inverse.inverse === bimap but that's not necessary.

如前所述,forcePut(K, V)方法可将线对(K1, V1)(K2, V2)替换为(K1, V2).首先,它判断K1的当前值,并将其从reverse映射中删除.然后找到值V2的键,并将其从direct映射中移除.然后该方法将给定的对插入到两个映射中.下面是它在代码中的外观.

override fun forcePut(key: K, value: V): V? {
  val oldValue = direct.put(key, value)
  oldValue?.let { reverse.remove(it) }
  val oldKey = reverse.put(value, key)
  oldKey?.let { direct.remove(it) }
  return oldValue
}

Implementations of Map and MutableMap methods are quite simple so I will not provide details for them here. They just perform an operation on both maps.

最复杂的部分是entrieskeysvalues.在我的实现中,我创建了一个Set,它将所有方法调用委托给direct.entries,并处理条目的修改.每次修改都发生在try/catch块中,这样在抛出异常时BiMap保持一致状态.此外,迭代器和可变项被包装在类似的类中.不幸的是,它使对条目的迭代效率大大降低,因为在每个迭代步骤上都会创建额外的MutableMap.MutableEntry个包装器.

Kotlin相关问答推荐

在KMM合成多平台中创建特定于平台的视图

如何避免使用公共类实现内部接口

Kotlin中是否可以混合使用推断和显式的通用类型参数?

在 Kotlin 中将两个字节转换为 UIn16

验证构造函数中的值组合

如何连接两个 kotlin 流?

为什么没有remember 的 mutableStateOf 有时会起作用?

SpringBoot 2.5.0 对于 Jackson Kotlin 类的支持,请在类路径中添加com.fasterxml.jackson.module: jackson-module-kotlin

Android 在将 androidx 生物识别更新为 1.0.0-alpha04 后崩溃

Anko 中的水平线性布局

Kotlin 中的部分类委托

什么是 .kotlin_builtins 文件,我可以从我的 uberjars 中省略它们吗?

retrofit 响应代码 405 并带有消息method not allowed here

Kotlin 语言是如何用 Kotlin 编写的?

主机名不能为空

Kotlin 的类型具体化使哪些在 Java 或 Scala 中无法实现的成为可能?

如何获取Kotlin中变量的名称?

如何将vararg作为数组传递给Kotlin中的函数?

如何在Kotlin中将字符串转换为InputStream?

Kotlin中对象和数据类的区别是什么?