Which methods are used for optimisation?

Hi All, i want to know which type of map initialisation is mostly preferred when optimizing your code:

  1. map[key] = map.getOrPut(key){ defaultValue} + someOperation
  2. map[key] = map[key]?.let{ it → someOperation} ?: defaultValue
  3. if(!map.contains(key)) { map.put(key, value) }

I also want to know, do you guys think about the which method to use to have more lower optimization or you depend upon kotlin ide or jetbrains to decide which method is more optimize?

I think the second one is the best because it inlines the let anyways.
Calling Map.contains() and then later Map.get() (the 3rd one is missing a bit of code to be equal to the other two) is not as efficient because Map.get() will return null if the element is not found. so effectively you are checking twice.
The problem with the first one, is that you are doing 1-2 puts, which you don’t need to do.

but 1st one can make code more readable than others? also 2nd one also have two operations like Map.get() and Map.put() which can be questionable, in terms of, efficiency of the statement with others

The first one has: get, (put), put
The second one: get, put
And the third one is way worse when you want it to be equal to the others

someOperation is a little enigmatic in your examples. Also, these examples aren’t really the same, e.g. in 1. you process the defaultValue through someOperation, but in 2. you don’t.

If you don’t mind using the Java API, there are ready to use compute and merge methods, which do exactly what you asked for. Additionally, they allow to do the whole operation atomically if using a concurrent map; and at least theoretically they could optimize this to search the map only once to perform both get and put, but I don’t know if any implementations do this.

1 Like

someOperation in 1st one is addition or subtraction like operations. It doesn’t process any defaultValue.

Yes, and again: if there is no value in the map, then in 1. you put defaultValue + someOperation, in 2. you put: defaultValue.

As for potential replacements for those examples you could rewrite them this way:

  1. map.compute(key) { _, value -> (value ?: defaultValue) + someOperation }
  2. map.compute(key) { _, value -> value?.let { it + someOperation } ?: defaultValue }
  3. map.putIfAbsent(key, value)

The main benefit of this approach is that each of them take only a single operation to execute, so it’s also good to use with concurrent maps.

1 Like

but how it is different from getOrPut? as compute only performs operation atomically while getOrPut will also make it more comprehensible to a reader and it help to understand code better.

First of all take into consideration that you are also replacing/inserting value to key at the end with map[key] = xxx. getOrPut() is just an inline function which first executes a lookup with get() and then executes a second operation using a classic put() method. In this case that second operation is completelly redundant. If you want to stick strictly to Kotlin functions you can use getOrElse() or getOrDefault() as alternatives.

1 Like

thanks. And do you know how to evaluate kotlin code and its method so that i can make a method chart mapped against how to use it and some metric to justify it’s usage.