How do I create a map from 2 arrays? - kotlin

I have a string array and an integer array. How do I create a map using the first as keys and the second as values?
val keys = arrayOf("butter", "milk", "apples")
val values = arrayOf(5, 10, 42)
val map: Map<String, Int> = ???
How to convert List to Map in Kotlin? doesn't solve this problem; I have 2 arrays and want a single map.

You can zip together the arrays to get a list of pairs (List<Pair<String, Int>>), and then use toMap to get your map.
Like this:
val keys = arrayOf("butter", "milk", "apples")
val values = arrayOf(5, 10, 42)
val map: Map<String, Int> =
keys.zip(values) // Gives you [("butter", 5), ("milk", 10), ("apples", 42)]
.toMap() // This is an extension function on Iterable<Pair<K, V>>

According to kotlin
Constructing Collections
-> creating a short-living Pair object, is not recommended only if performance isn't critical and to quote: "To avoid excessive memory usage, use alternative ways. For example, you can create a mutable map and populate it using the write operations. The apply() function can help to keep the initialization fluent here."
since I'm not much of an expert I run on to these code and maybe this should work better?:
val numbersMap = mutableMapOf<String,Int>()
.apply{ for (i in 1.. 5) this["key$i"] = i }
println(numbersMap)
//result = {key1=1, key2=2, key3=3, key4=4}
or to adjust it to question above - something like this:
val keys = arrayOf("butter", "milk", "apples")
val values = arrayOf(5, 10, 42)
val mapNumber = mutableMapOf<String, Int>()
.apply { for (i in keys.indices) this[keys[i]] = values[i] }
println(mapNumber)

Related

Kotlin, is it possible to access the pair of a map?

Is it possible to access the whole Pair of a map, not only the key or a value?
Let's say we have a map
map = mapOf(Pair("Example1", 1), Pair("Example2", 2), Pair("Example3",
3))
I would like to access the second pair and put it into a variable, something like I would do with a list:
val ex2 = map[1] #this would result with {"Example2", 2}
And then i would be able to access the pair's key/value like:
ex2.key / ex2.value
More specifically, I would like to use this in my function to return a specific pair of the map.
Not sure if this would help
val mapString = mutableMapOf(1 to "Person", 2 to "Animal")
val (id, creature) = 1 to mapString.getValue(1)
Log.e("MapPair", "$id, $creature")
prints
1, Person
or if you're iterating through the entire map
mapString.forEach {
val (id, creature) = it.key to it.value
Log.e("MapPair", "$id : $creature")
}
prints
1 : Person
2 : Animal
or using Pair
val key = 1
val pair = Pair(key, mapString.getValue(key))
Log.e("MapPair", "$pair")
prints
(1, Person)
or if you're iterating through the entire map using Pair
mapString.forEach {
val pair = Pair(it.key, it.value)
Log.e("MapPair", "$pair")
}
prints
(1, Person)
(2, Animal)
Update: For iterating through the map you can also go with Destructuring Declarations
val mapString = mutableMapOf(1 to "Person", 2 to "Animal")
for ((key, value) in mapString) {
Log.e("MapComponents", "$key, $value")
}
From your comment, it seems like you want to fetch the key corresponding to a given value.
val map = mapOf("Chicken" to 20, "Egg" to 10, "Bread" to 5)
val valueToFind = 20
val key = map.toList().find { it.second == valueToFind }?.first
println(key)
Output:
Chicken
If the value doesn't exist, it will give null.

Sum Mutable Map values inside a list of objects kotlin

I have a data class in Kotlin like this:
data class Activity(
var id: String? = "",
var prize: MutableMap<String?, Int?>? = null
)
And a list of this object:
var myList = listOf(Activity("A", prize={day_5=70, day_4=70}),
Activity("B", prize={day_5=40, day_4=80}))
The desired result is:
Activity("A", prize={total=140}),
Activity("B", prize={total=120})
So basically I want to sum the values of the prize map inside of each object.
I think that has something to do with transformation but I'm new to Kotlin and I couldn't find any resources over the internet, or maybe they were to complicated.
This algorithm is easy, just iterating through all the maps and replace elements with the sum:
val myList = listOf(
Activity("A", hashMapOf("day_5" to 70, "day_4" to 70)),
Activity("B", hashMapOf("day_5" to 40, "day_4" to 80)),
)
for (i in myList) {
val total = i.prize.values.sum()
i.prize.clear()
i.prize["total"] = total
}

Create list of lists in kotlin?

How do I create a list of lists?
I have a mutable list of ints:
val rsrpList = mutableListOf<Int>()
Now I am trying to create a list of lists, like this:
val rsrpList = mutableListOf<Int>()
val rsrqList = mutableListOf<Int>()
val levelList = mutableListOf<Int>()
val listoflists = List<List<Int>>
listoflists.add(rsrpList)
listoflists.add(rsrqList)
listoflists.add(levelList)
but I know this is wrong, because I'm adding a list one at a time, instead of a list of lists. How would I do this?
You can do this with the Kotlin Standard Library. Both List and MutableList can be created to a specific size (3 in this case) and specify a lambda that will initialize each value.
val listOfList = MutableList(3) { mutableListOf<Int>() }
Or:
val listOfList = List(3) { mutableListOf<Int>() }
Update: To initialize a List with precreated lists:
val listOfList = listOf(list1, list2, list3)
Or in your specific case:
val listOfList = listOf(rsrpList, rsrqList, levelList)
And in both cases you can replace listOf with mutableListOf if you want a mutable list as the main type.
Your example is fine (you have an empty list, you're adding lists to that list, you end up with a list of lists!) but if you're trying to avoid mutability by declaring everything at once:
val listOfLists = listOf(rsrpList, rsrqList, levelList)
and you can declare those lists at the same time if you want
val listOfLists = listOf(
listOf(1, 2, 3),
listOf(9, 8, 7),
listOf(7, 7, 7)
)
or you can use mutableListOf if you need any of them to be mutable! The formatting there isn't necessary, I just think it looks clearer how they're nested

In Kotlin, how can I take the first n elements of an array

In Kotlin, how can I take the first n elements of this array:
val allColours = arrayOf(
Pair(Color.RED, Color.WHITE),
Pair(Color.RED, Color.BLACK),
Pair(Color.YELLOW, Color.BLACK),
Pair(Color.GREEN, Color.WHITE),
Pair(Color.BLUE, Color.WHITE),
Pair(Color.BLUE, Color.WHITE),
Pair(Color.CYAN, Color.BLACK),
Pair(Color.WHITE, Color.BLACK))
So how can I fill pegColours with the first say 3 Pairs?
var pegColours: Array<Pair<Color,Color>> = //???
I tried allColours.take but it gave an error:
Expecting an element
You need to specify the number of items you want to take.
allColours.take(3)
For a random number of random indices, you can use the following:
val indexes = arrayOf(2, 4, 6)
allColours.filterIndexed { index, s -> indexes.contains(index) }
Note that you can write an extension method for this:
fun <T> Array<T>.filterByIndices(vararg indices: Int) = filterIndexed { index, _ -> indices.contains(index) }
Alternatively, if the indices are consecutive, you can use slice:
allColours.slice(1..3)
The problem with your code that you create pairs with color constants which are Ints (allColours has type Array<Pair<Int, Int>>), but you expect Array<Pair<Color, Color>>. What you have to do is change type pegColours type and use take:
var pegColours: Array<Pair<Int, Int>> = allColours.take(3).toTypedArray()
Also you have to call toTypedArray() cause Array.take returns List rather than Array. Or you can change pegColours type as following:
var pegColours: List<Pair<Int, Int>> = allColours.take(3)
I know you already proposed the usage of take, but alternatively ranges and a simple map also help to write idiomatic code as shown next:
var pegColours = (0 until 3)
.map { allColours[it] }
.toTypedArray()
You are very close :)
val allColours = arrayOf("red", "blue", "green")
kotlin.io.println(allColours.take(2))
Will give you first two elements ["red", "blue"]
You have to specify the number of elements you want to take from the array

What is the smartest way to copy a Map in Kotlin?

I'd like to get a new instance of some Map with the same content but Map doesn't have a built-in copy method. I can do something like this:
val newInst = someMap.map { it.toPair() }.toMap()
But it looks rather ugly. Is there any more smarter way to do this?
Just use the HashMap constructor:
val original = hashMapOf(1 to "x")
val copy = HashMap(original)
Update for Kotlin 1.1:
Since Kotlin 1.1, the extension functions Map.toMap and Map.toMutableMap create copies.
Use putAll method:
val map = mapOf("1" to 1, "2" to 2)
val copy = hashMapOf<String, Int>()
copy.putAll(map)
Or:
val map = mapOf("1" to 1, "2" to 2)
val copy = map + mapOf<String, Int>() // preset
Your way also looks idiomatic to me.
The proposed way of doing this is:
map.toList().toMap()
However, the java's method is 2 to 3 times faster:
(map as LinkedHashMap).clone()
Anyway, if it bothers you that there is no unified way of cloning Kotlin's collections (and there is in Java!), vote here: https://youtrack.jetbrains.com/issue/KT-11221
Add this extension (to convert entries to pairs)
val <K, V> Map<K, V>.pairs: Array<Pair<K, V>>
get() = entries.map { it.toPair() }.toTypedArray()
And then you can easy combine immutable maps using default Kotlin syntax.
val map1 = mapOf("first" to 1)
val map2 = mapOf("second" to 2)
val map3 = mapOf(
*map1.pairs,
"third" to 3,
*map2.pairs,
)