简体   繁体   English

如何仅通过一次地图查找来增加给定键的值?

[英]How to increment value of a given key with only one map lookup?

Say I have a map:假设我有一张地图:

 var inventory = mutableMapOf("apples" to 1, "oranges" to 2)

and I want to increment the number of apples by one.我想把苹果的数量加一。

However this does not work:但是,这不起作用:

inventory["apples"]!!++ // Error:(9, 4) Variable expected

This neither:这既不是:

var apples = inventory["apples"]!!
++apples
println(inventory["apples"]) // prints "1" => the value was not incremented.

Which is surprising, since in Kotlin, numbers are boxed when they are stored in instances of generic objects .这是令人惊讶的,因为在 Kotlin 中,数字在存储在通用对象的实例中时会被装箱 I would not expect that a copy is being made.我不希望正在制作副本。

It seems that the only way is to do something like:似乎唯一的方法是做这样的事情:

var apples = inventory["apples"]!!
++apples
inventory["apples"] = apples
println(inventory["apples"]) 

Which both uses two lookups in the map and is extremely ugly and lengthy.这两者都在地图中使用了两次查找,并且非常丑陋和冗长。

Is there a way to increment a value of a given key using only one lookup?有没有办法只使用一次查找来增加给定键的值?

Also, could someone explain why the first two methods do not work?另外,有人可以解释为什么前两种方法不起作用吗?

There is no way to increment the value with only one get and without a put .没有办法只用一个get而不用put来增加值。 You always need to do a put afterwards, because Int is immutable.你总是需要在之后做一个put ,因为Int是不可变的。 The inc() method ( ++ is a shortcut for that) returns a new value that need to be stored in the map. inc()方法( ++是它的快捷方式)返回一个需要存储在映射中的新值。 It does not change the stored value.它不会改变存储的值。

You can use您可以使用

inventory.computeIfPresent("apples") { _, v -> v + 1 }

To write it in one line, but if you look into the implementation it will also do a get() then compute the new value and do a put() afterwards.将它写在一行中,但如果您查看实现,它也会执行get()然后计算新值并在之后执行put() So you can save a line of code you have to write, but you will not save CPU cycles on execution time.因此,您可以节省必须编写的一行代码,但不会节省执行时间的 CPU 周期。

Try this:尝试这个:

inventory.computeIfPresent("apples") { _, v -> v + 1 }

The first two methods don't work because when you retrieve a value from the map you get a primitive type, in your case Integer , which is immutable.前两种方法不起作用,因为当您从地图中检索值时,您会得到一个原始类型,在您的情况下是Integer ,它是不可变的。 When you change the value of an Integer you're simply pointing your variable at a new instance of Integer, you're not updating that Integer instance which you were previously pointing at.当您更改 Integer 的值时,您只是将变量指向 Integer 的新实例,而不是更新您之前指向的那个 Integer 实例。

As Integers are boxed in maps, Integer is a primitive wrapper class, and primitive wrapper classes are immutable in Java , it seems that you'd like to mutate an immutable object, which is unfortunately not possible, at least not by any conventional or recommended means.由于整数被装箱在地图中, Integer是一个原始包装类,而原始包装类在 Java 中是不可变的,似乎您想改变一个不可变对象,不幸的是这是不可能的,至少不是任何传统或推荐的方法。

Take a look at Most efficient way to increment a Map value in Java , where there are several suggestions on how to improve the performance of integer value incrementing in maps, as well as one explicitly implementing your desired behavior through a wrapper class MutableInt , which also turns out to be the fastest (~20% faster than the baseline).看看在 Java 中增加 Map 值的最有效方法,其中有一些关于如何提高地图中整数值递增性能的建议,以及通过包装类MutableInt显式实现所需行为的MutableInt ,这也结果证明是最快的(比基线快约 20%)。

The computeIfPresent method in java.util.HashMap only does one lookup . java.util.HashMap 中的computeIfPresent方法只进行一次查找 So you can use:所以你可以使用:

var inventory = hashMapOf("apples" to 1, "oranges" to 2)
inventory.computeIfPresent("apples") { _, v -> v + 1 }  // Only 1 lookup!

Note: this is an implementation detail.注意:这是一个实现细节。 It does one lookup in the current version of Kotlin (1.3.11) using a specific implementation of Java (Oracle HotSpot 11.0.1).它使用特定的 Java 实现(Oracle HotSpot 11.0.1)在当前版本的 Kotlin (1.3.11) 中进行一次查找。 Other configurations may or may not use different ways.其他配置可能会或可能不会使用不同的方式。

Another idea另一个想法

// Declaration
val map = mutableMapOf<String, Int>()
// Increment
map.put("x", map.getOrPut("x"){ 1 } + 1)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM