I want to use nested pair in kotlin, such as "a" to {"b" to "c"}
I have tried :
"teachers" to {"a" to "c"; "c" to "d"}
but when I debug this, the data type is:
(teachers, () -> kotlin.Pair<kotlin.String, kotlin.String>)
how to use this?
if don't use
"a" to mapOf("a" to "b"...)
Is it possible?
{ A -> B } is an anonymous function whose parameter is A and body is B.
{ B } is a short form of { () -> B }.
In addition,
A; B
is the same as
A
B
Therefore {"a" to "c"; "c" to "d"} means a function whose parameter list is () (zero parameters) and body is
Pair("a", "c")
Pair("c", "d")
which is equivalent to something like ::noName with
fun noName() {
Pair("a", "c")
return Pair("c", "d")
}
Anyway, what are the braces in your code? They do not mean "pairs." I think you meant to represent a map (or dictionary) in python, but PAIRS ARE NOT MAPS and vice versa.
Nested pair is something like this: "a" to ("b" to "c") which is equivalent to Pair("a", Pair("b", "c"))
If you want to make a map in Kotlin, you should use function mapOf().
If you want to make an array of pairs in Kotlin, you can do so like arrayOf("a" to "b", "c" to "d").
Also, arrays are not maps and vice versa.
This is an example of (a pair of (a string) and (an array of (pairs of strings))).
"a" to arrayOf("b" to "c", "d" to "e")
Related
So basically the title I want to change the word letters to another word but it says I have to specify the parameter
fun main() {
val dictionary = mapOf( "c" to "b", "a" to "d" , "r" to "e"//here is the letters i want to change
)
val letters = "car"//the word i want to change
for (me in letters){
println(dictionary[me])
}
}
i want for "car" to be "bde"
Notice that your map has strings as keys, because you used string literals in these places:
val dictionary = mapOf( "c" to "b", "a" to "d" , "r" to "e")
*** *** ***
However, when you access the map, you are accessing it using me, which is a Char you got from the string letters. This causes the error.
I would suggest that you change the map to use Char keys instead. Change the string literals to character literals:
val dictionary = mapOf( 'c' to "b", 'a' to "d" , 'r' to "e")
*** *** ***
Notice that the letters are now surrounded with single quotes.
Though it is not required to solve this particular problem, you can also change the map's values to character literals too.
After that, you should use print instead of println to print the map values out, so that they are all printed on the same line:
for (me in letters){
print(dictionary[me] ?: me.toString())
}
Note that I added the ?: me.toString() part so that if no replacement was found in the map, the original letter would be printed.
If you want a single string as the result, rather than having it printed out,
val result = letters.map { dictionary[it] ?: it.toString() }.joinToString("")
I have two collections: A and B. Both of them consist of equal amount of chars. I zip them. Then I need to count pairs of the same elements, like 'A' and 'A'. I need to write a predicate, but I can't find the way to get both elements from a zipped collection.
I've tried something like this:
val num = A.zip(B).count { it.i: Int, it.j:Int -> it.i == it.j}
and this:
val num = A.zip(guess).count { it[0] == it[2] }
But it doesn't work. How can I reach both elements from these sub lists of chars?
I looked into Kotlin official examples but there are only easy ones:
val evenCount = numbers.count { it % 2 == 0 }
In order to deconstruct the resulting Pair given by .zip when using .count, you need to put the "deconstructor" into parentheses.
a.zip(b).count { (aElement, bElement) -> aElemant == bElement }
You could also just ignore that and just access it directly.
a.zip(b).count { it.first == it.second }
If you want to count the pairs of elements in two lists, you're very close. By calling zip you are given a Pair. You can count the resulting list of Pair objects by accessing their first and second parts and seeing if they match (using ==).
// Assumptions...
val a = listOf("A", "B", "D")
val b = listOf("A", "B", "C")
// Count where both elements of the zipped pair match
return a.zip(b).count { it.first == it.second }
I have two maps and I want to merge using some rules
val a = mapOf(1 to 101, 2 to 102, 3 to 103)
val b = mapOf(101 to "a", 102 to "b", 103 to "c")
is there a way to merge using values for a and key for b
val result = mapOf(1 to "A", 2 to "b", 3 to "c")
Since the values of a and the keys of b will always match, you can do this with a single mapValues
val result = a.mapValues { (_, v) -> b.getValue(v) }
getValue can be safely used here since the key v always exist in b as a consequence of our assumption.
In general, if b may not have all the values of a as keys, you can do:
val result = a.entries.mapNotNull { (k, v) -> b[v]?.let { k to it } }.toMap()
This removes the key from the result, if the key's corresponding value in a doesn't exist as a key in b. You can also use this as an alternative if you don't like the !! in the first solution.
mapNotNull and toMap loops through the entries one time each. If that is a problem for you, use asSequence:
a.asSequence().mapNotNull { (k, v) -> b[v]?.let { k to it } }.toMap()
Since you're sure each value from map a is present in map b, this should be as simple as using mapValues and using the value of that key in map b
a.mapValues { entry ->
b[entry.value]
}
Due to having to edit and redo my answer, #Sweeper beat me to it and provided a more in-depth answer.
I have the following Java 11 code (the contents of arr1 and arr2 are not so simple in my code, and I have more than 2 arrays, but the concept is the same):
String[] arr1 = new String[] {"a","b"};
String[] arr2 = new String[] {"c", "d"};
var req = Stream.of(arr1, arr2).flatMap(Stream::of).toArray(String[]::new);
The purpose of this code is to take all the values in multiple arrays of Strings and produce a single String array out. It needs to be an array, not a collection, due to an API outside my control accepting a String array later in the code.
In this simple example, the resulting array should have the following elements in this order: { "a", "b", "c", "d" }.
What is the canonical way to flatten a 1-deep array of arrays into a single array in Kotlin?
The main reason I'm being thrown for a loop here is that the IntelliJ Java to Kotlin converter did a pretty bad job of converting this code, leaving it with multiple weird syntax errors in the output Kotlin. The rest of my code that doesn't use things like method references converted much more cleanly to Kotlin.
I don't know about canonical, but perhaps the simplest equivalent is:
val arr1 = arrayOf("a", "b")
val arr2 = arrayOf("c", "d")
val req = arrayOf(arr1, arr2).flatten().toTypedArray()
That creates an Array<String> with the four values you want.
Here we're not transforming the values, simply repackaging them, so flatten() is simpler than the more common flatMap.
(It's normally better to use lists and other collections — the standard library has much better support for them, as well as avoiding issues around generics and type erasure — but having to interoperate with an old or badly-designed API, as specified in this question, is one of the corner cases you may still need arrays for, along with varargs and low-level collection implementation.)
The easiest in Kotlin would be:
val arr1 = arrayOf("a", "b")
val arr2 = arrayOf("c", "d")
val result = arrayOf(arr1, arr2)
.flatten()
.toTypedArray()
flatten() creates a List and toTypedArray() converts it to an array. This could be considered a waste of CPU cycles, but on the other hand, I don't see a way to create an array from a lazy stream/sequence directly, because we don't know the resulting size. So my guess would be that Java's Stream.toArray() also copies the data several times in the process (?).
If we need to limit copying to the minimum, we can create our own extension:
inline fun <reified T> Array<out Array<out T>>.flattenToArray(): Array<T> {
val result = arrayOfNulls<T>(sumOf { it.size })
var pos = 0
for (arr in this) {
arr.copyInto(result, pos)
pos += arr.size
}
#Suppress("UNCHECKED_CAST")
return result as Array<T>
}
If you literally just want to put them in a single array, you can use the spread operator
val arr1 = arrayOf("a", "b")
val arr2 = arrayOf("c", "d")
val result = arrayOf(*arr1, *arr2)
I'm not sure there's a way to do that for an arbitrary number of source arrays, so if you need that, then flatten is the way to go. This is quick and easy for unpacking a specific bunch of arrays though
.flatten() should do the job.
val arr1 = arrayOf("a", "b")
val arr2 = arrayOf("c", "d")
arrayOf(arr1, arr2).flatten()
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/flatten.html
flatten() is the simple way to do it. All the standard array and Iterable operators return Lists. If you actually need an array, you can call toTypedArray() on the returned List.
You can start by combining them into a List or Array.
val arr1 = arrayOf(“a”, “b”)
val arr2 = arrayOf(“c”, “d”)
val req = listOf(arr1, arr2).flatten() //.toTypedArray()
I would like to transform the Map to List
e.g I have
mapOf("a" to listOf(1,2),
"b" to listOf(3,4)
)
I want the result to be
listOf("a", 1, 2, "b", 3, 4)
order must be Key and its Values, Key and its Values, ...
is there some function in kotlin that could help me with that?
My second comment variant as answer for a Map<String, List<Int>>:
mapOf("a" to listOf(1,2),
"b" to listOf(3,4))
.flatMap { (key, values) -> listOf(key) + values }
which gives a List<Any> with the keys followed by their values.
This example makes use of destructuring declaration and Map.flatMap.
UPDATE: the answer below was written before the question was updated and changed how the map was created (see the history of the question for details). As the question now stands, the answer below will no longer work. It does work for the question as originally asked though, I believe.
#Roland is right that your map will never result in that list because there can only ever be a single value in the map against any given key. So I think you need to replace that map with a list of pairs. You can then group it and flatmap it to get your desired result:
val pairs = listOf("a" to 1, "a" to 2, "b" to 3, "b" to 4)
val result = pairs
.groupBy { it.first }
.flatMap { (key, values) -> listOf(key).plus(values.map { it.second }) }
Another slightly different option which you might decide is more readable is this:
val result = pairs
.groupBy({ it.first }, { it.second })
.flatMap { (key, values) -> listOf(key).plus(values) }
You can flatMap over map.entries. Have a look at this function:
val map = mapOf("a" to listOf(1,2),
"b" to listOf(3,4))
println(map)
val flattened : List<Any> = map.entries.flatMap {entry ->
//create list with key as only element, must be type <Any> to add other stuff later
val list = mutableListOf<Any>(entry.key)
//add values
list.addAll(entry.value)
list
}
println(flattened)
prints:
{a=[1, 2], b=[3, 4]}
[a, 1, 2, b, 3, 4]
#Rolands answer inspired this even simpler, more idiomatic version. It essentially does the same, but crams everything into one line:
val flattened: List<Any> = map.flatMap {entry ->
listOf(entry.key) + entry.value
}