In Kotlin you can extract list items using a step like this:
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.slice(0..4 step 2))
Is there a similar way to do this for a map? So instead of listOf, I'm using mapOf.
First you need to think about whether it makes sense to use slice on a Map. The Map interface does not guarantee an order, so it does not have the concept of indices that you can select from, which is what slice does.
If your Map is backed by a specific implementation that guarantees an iteration order, such as LinkedHashMap, then it can make sense to convert the Map's entries into a List so you can slice them, and then you can convert the result back to a Map.
val result = someLinkedHashMap
.entries
.toList()
.slice(someRange)
.associate { it.key to it.value } // change the filtered entries list into a new map
The associate function's documentation guarantees a Map implementation that has consistent execution order.
slice() is an extension function for Arrays and Lists.
To convert a Map to a List, first get the entries Set, and then convert the Set into a List.
Run in Kotlin Playground
fun main() {
val numbers = mapOf(
"one" to 1,
"two" to 2,
"three" to 3,
"four" to 4,
"five" to 5,
"six" to 6,
)
// get the Map entries, and convert them to a List - then slice
val sliced = numbers.entries.toList().slice(0..4 step 2)
println(sliced)
}
Output:
[one=1, three=3, five=5]
Related
here is example of the list. I want to make dynamic where maybe the the value will become more.
val list = arrayListOf("A", "B", "C", "A", "A", "B") //Maybe they will be more
I want the output like:-
val result = list[i] + " size: " + list[i].size
So the output will display every String with the size.
A size: 3
B size: 2
C size: 1
If I add more value, so the result will increase also.
You can use groupBy in this way:
val result = list.groupBy { it }.map { it.key to it.value.size }.toMap()
Jeoffrey's way is better actually, since he is using .mapValues() directly, instead of an extra call to .toMap(). I'm just leaving this answer her since
I believe that the other info I put is relevant.
This will give a Map<String, Int>, where the Int is the count of the occurences.
This result will not change when you change the original list. That is not how the language works. If you want something like that, you'd need quite a bit of work, like overwriting the add function from your collection to refresh the result map.
Also, I see no reason for you to use an ArrayList, especially since you are expecting to increase the size of that collection, I'd stick with MutableList if I were you.
I think the terminology you're looking for is "frequency" here: the number of times an element appears in a list.
You can usually count elements in a list using the count method like this:
val numberOfAs = list.count { it == "A" }
This approach is pretty inefficient if you need to count all elements though, in which case you can create a map of frequencies the following way:
val freqs = list.groupBy { it }.mapValues { (_, g) -> g.size }
freqs here will be a Map where each key is a unique element from the original list, and the value is the corresponding frequency of that element in the list.
This works by first grouping elements that are equal to each other via groupBy, which returns a Map<String, List<String>> where each key is a unique element from the original list, and each value is the group of all elements in the list that were equal to the key.
Then mapValues will transform that map so that the values are the sizes of the groups instead of the groups themselves.
An improved approach, as suggested by #broot is to make use of Kotlin's Grouping class which has a built-in eachCount method:
val freqs = list.groupingBy { it }.eachCount()
I have a list of ids. I want to filter my list and only keep the values in that list that match the id.
fun filterHelper(ids: List<Int>, list: List<People>) {
list.filter { ids.contains(it.id) }
}
But this is very inefficient. It is essentially traversing the list O(n^2). Does Kotlin let me do better?
I asked a similar question about slicing maps recently. The answer is that there is no good built-in function, but you can work around by using a Set instead of a List for your ids, which gets you O(1) lookup time for the comparisons, so O(n) in total.
data class People(val id: Int)
fun main() {
val people = listOf(People(1), People(2), People(3), People(4))
val ids = setOf(2, 4)
val filtered = people.filter { it.id in ids }
println(filtered)
}
Output:
[People(id=2), People(id=4)]
It's worth mentioning that if you already have a list, you can easily convert to a set with:
list.toSet()
Why cannot I sort a mutable map of string. My map is declared as follows.
val schedule: MutableMap<String, ArrayList<String>>
It gives me schedule object as follows.
{1=[1], 0=[0], 3=[3], 2=[2], 5=[5], 4=[4, 14.07, 16.07, 01.08, 10.08], 6=[6]}
Now for day 4, I would to sort the elements in ascending order, ideally ignoring first element. I want my output to look like below.
{1=[1], 0=[0], 3=[3], 2=[2], 5=[5], 4=[4, 1.08, 10.08, 14.07, 16.07], 6=[6]}
I can access the required day with schedule.schedule["4"]?.sorted()
but this doesn't do anything. I tired converting Strings to Ints but still no luck.
Use sort() instead of sorted().
sort() sorts "in place": it mutates the ArrayList
sorted() returns a new sorted ArrayList
Try it: https://repl.it/repls/BitterRapidQuark
val map = mutableMapOf("4" to arrayListOf<String>("4", "14.07", "16.07", "01.08", "10.08"))
println("Original: " + map) // {4=[4, 14.07, 16.07, 01.08, 10.08]}
map["4"]?.sorted()
println("Not mutated: " + map) // {4=[4, 14.07, 16.07, 01.08, 10.08]}
map["4"]?.sort()
println("Mutated: " + map) // {4=[01.08, 10.08, 14.07, 16.07, 4]}
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
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)