This question already has answers here:
Kotlin Error: Unresolved reference: merge (for list.merge())
(2 answers)
Closed 3 years ago.
i'm reading anotonio leava book about kotlin
there is a function named "merge" it can merge two list with each other
this is a code that author write in his book:
val list = listOf(1,2,3,4,5,6)
val anotherlist = listOf(7,8,9,10,11,12)
assertEquals(listOf(8,10,12,14,16,18),list.merge(anotherlist){it1,it2 - > it1+it2})
it means merge is plusing two list
but when i write code myself
my idea intelij doesnt know the func name
and it doesnt work
can you help me
sorry because of my english
You can do it with the use of map
val x: List<Int> = listOf(1,2,3,4,5,6)
val y: List<Int> = listOf(2,3,4,5,6,7)
val sums = (x.indices).map { x[it] + y[it] }
output
[3, 5, 7, 9, 11, 13]
instead of map you can use zip function
fun main(args: Array<String>) {
val list1 = listOf(4, 5, 6)
val list2 = listOf(1, 2, 3)
val result = list1.zip(list2) { e1, e2 -> e1 + e2 }
println(result) // prints [5, 7, 9]
}
merge is neither a member function of List, nor does the kotlin standard library provide an extension function. But you can define one by your own (and I suspect, that's what the author did)
fun <E> List<E>.merge(anotherlist: List<E>, operation: (E, E) -> E): List<E> {
// you probably want to check cardinalities of the two lists
return indices.map { operation(this[it], anotherlist[it]) }
}
Related
I'm solving exercises for a programming book in Kotlin. The task is to implement function using "zip()" and return a "List" of Pairs, where the first item in a "Pair" is the element, and the second item is the index of that element.
I solved the exercise, the solution works but I cannot understand the book solution.
Here is mine solution:
fun zipWithIndex(listToTake: List<Any>): List<Pair<Any, Any>> {
val finalList = mutableListOf<Any>()
var num = 0
for(element in listToTake) {
finalList += num
num ++
}
return (listToTake zip finalList)
}
fun main() {
val listToCall = listOf<String>("a", "b", "c")
println(zipWithIndex(listToCall))
}
And here is the book solution:
fun <T> List<T>.zipWithIndex(): List<Pair<T, Int>> =
zip(indices)
fun main() {
val list = listOf('a', 'b', 'c')
list.zipWithIndex() eq
"[(a, 0), (b, 1), (c, 2)]"
}
Can somebody please explain how does the book solution get the indexes of the elements in the list or tell me the topic that I need to read about to figure out how the code from the book works.
Thanks in advance for any help.
indices is a property of every kotlin List: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/#extension-properties
It's an IntRange of all valid indices, so essentially the range (https://kotlinlang.org/docs/ranges.html) equivalent of [0, 1, 2]. An IntRange is an Iterable, so it can be zipped with (the third zip overload in the api docs of list).
So it is equivalent to the zip you did, except you constructed [0, 1, 2] yourself while they used the pre-existing property of the List.
They also defined an extension function on List (https://kotlinlang.org/docs/extensions.html#extension-functions) instead of passing the list as a parameter.
For example we have such array:
val listArr = listOf(1,2,3,4,5,6,7)
and finally we receive:
1,2,3,4,5,6,7
maybe it is possible to write something like that:
val listArr = listOf(1..7)
and receive similar result. Or it is impossible right now?
You can use the IntRange.toList() function:
val list = (1..7).toList()
Ranges are automatically converted to lists when concatenating:
val combined = (1..6) + 12 + (34..37)
// [1, 2, 3, 4, 5, 6, 12, 34, 35, 36, 37]
RobCo's answer is correct and answers the question asked.
About the followup question you asked in the comment to his answer:
how we can use such solution in another list for example 1,2,3,4,5,6,12,34,35,36,37
You could write a new function that accepts ranges:
fun customListOf(vararg ranges: IntRange) = ranges.flatMap { it.toList() }
Then use it like this:
fun main() {
val list = customListOf(1..6, 12..12, 34..37)
println(list)
}
Output:
[1, 2, 3, 4, 5, 6, 12, 34, 35, 36, 37]
However, you need to pass a range even for a single value like 12..12 above.
If you wanted to be hacky, you could write a function that accepts a vararg range: Any, and use reflection to check the type at runtime. That would allow you to mix ranges and ints in the same call:
fun hackyCustomListOf(vararg rangeOrInt: Any) = rangeOrInt.flatMap {
when (it) {
is IntRange -> it.toList()
is Int -> listOf(it)
else -> throw IllegalArgumentException("Expected an IntRange or an Int, got ${it::class}")
}
}
Usage:
fun main() {
val list1 = hackyCustomListOf(1, 5, 12..15, 25, 99..102)
println(list1)
val list2 = hackyCustomListOf(1..3, "boom", 5.0)
println(list2)
}
Output:
[1, 5, 12, 13, 14, 15, 25, 99, 100, 101, 102]
Exception in thread "main" java.lang.IllegalArgumentException: Expected an IntRange or an Int, got class kotlin.String
at TestKt.hackyCustomListOf(test.kt:7)
at TestKt.main(test.kt:14)
at TestKt.main(test.kt)
This removes compile-time checks on the argument, so I don't think it's a good idea. Fun exercise, though.
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
}
How can I use Stack (from java) in Kotlin?
Or theres any other alternative?
I'm trying to convert list to Stack
Kotlin 1.3.70 introduced the kotlin.collections.ArrayDeque class, which functions as both a queue and a stack, like Java's java.util.Deque (Deque meaning "double-ended queue"). It was created out of a necessity for a multiplatform ArrayDeque implementation.
val stack = ArrayDeque(listOf(1, 2, 3)) // stack: [1, 2, 3]
stack.addLast(0) // stack: [1, 2, 3, 0] (push)
val value = stack.removeLast() // value: 0, stack: [1, 2, 3] (pop)
Note that if an ArrayDeque is empty when you call removeFirst or removeLast, it will throw a kotlin.NoSuchElementException. If you don't want to check the size of your deque every time you need to access it, then you should use the removeFirstOrNull and removeLastOrNull functions.
Optional Snippets
ArrayDeque constructor function:
inline fun <T> arrayDequeOf(vararg elements: T) = ArrayDeque(elements.toList())
// ...
val stack = arrayDequeOf(1, 2, 3)
Stack-like ArrayDeque calls:
inline fun <T> ArrayDeque<T>.push(element: T) = addLast(element) // returns Unit
inline fun <T> ArrayDeque<T>.pop() = removeLastOrNull() // returns T?
import java.util.ArrayDeque
var stack = ArrayDeque<Int>()
stack.push(1)
stack.push(2)
stack.push(3)
stack.push(4)
println(stack) // --> [4, 3, 2, 1]
println(stack.isEmpty()) // --> false
println(stack.peek()) // --> 4
println(stack) // --> [4, 3, 2, 1]
println(stack.pop()) // --> 4
println(stack) // --> [3, 2, 1]
stack.push(9)
println(stack) // --> [9, 3, 2, 1]
You can use following:
/**
* Stack as type alias of Mutable List
*/
typealias Stack<T> = MutableList<T>
/**
* Pushes item to [Stack]
* #param item Item to be pushed
*/
inline fun <T> Stack<T>.push(item: T) = add(item)
/**
* Pops (removes and return) last item from [Stack]
* #return item Last item if [Stack] is not empty, null otherwise
*/
fun <T> Stack<T>.pop(): T? = if (isNotEmpty()) removeAt(lastIndex) else null
/**
* Peeks (return) last item from [Stack]
* #return item Last item if [Stack] is not empty, null otherwise
*/
fun <T> Stack<T>.peek(): T? = if (isNotEmpty()) this[lastIndex] else null
This is done in the same way as you would in Java, but with Kotlin syntax - notably different are the val keyword and lack of new keyword. For example:
import java.util.Stack
...
val someList = ArrayList()
...
val stack = Stack()
stack.addAll(someList)
This is a few years old but I suspect there's room for a different approach. If you want to use a stack structure in Kotlin you certainly don't need to resort to Java. You could easily just create a new class with an internal Kotlin list and stack-like public functions, or use Kotlin's extension methods to give an existing Kotlin collection "stack-like" functionality, for example:
fun <T> MutableList<T>.push(item: T) = this.add(this.count(), item)
fun <T> MutableList<T>.pop(): T? = if(this.count() > 0) this.removeAt(this.count() - 1) else null
fun <T> MutableList<T>.peek(): T? = if(this.count() > 0) this[this.count() - 1] else null
fun <T> MutableList<T>.hasMore() = this.count() > 0
Then, optionally, you could use a typealias to make it more obvious what you're trying to do when using those functions:
typealias Stack = MutableList<MyClass>
Then create one and use it:
val myStack: Stack = mutableListOf()
myStack.push(MyClass())
myStack.pop()
etc
you can define Stack like it.
val stack = Stack<YourStackType>()
notice that set the data type of your stack, for example stack of Int is like this:
val stack = Stack<Int>()
after that you can use push , pop , or other stack operations
example for Int stack :
a:Int = 10
stack.push(a)
a = stack.pop()
I don't believe there's a specific separate implementation of Stack in Kotlin. You could definitely use the answer by Ed.
Alternatively, you could use a mutableListOf<DataType> construct, and then have custom methods that are on top of this.
It would be something like this :
var stackDemo = mutableListOf<String>()
To push an element
var count = stackDemo.count()
stackDemo.add(count,"One")
To pop an element
var count = stackDemo.count()
stackDemo.removeAt(count)
You can refer to this Github link for a model implementation
Take the following one-liner, which can be expressed as a series of operations on a collection or a sequence:
val nums = (10 downTo 1)
// .asSequence() if we want this to be a sequence
.filter { it % 2 == 0 }
.map { it * it }
.sorted()
// .asList() if declaring it a sequence
println(nums) // [4, 16, 36, 64, 100]
Let's say I want to see the elements at each step, they would be (from deduction):
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[10, 8, 6, 4, 2]
[100, 64, 36, 16, 4]
[4, 16, 36, 64, 100]
Unfortunately, there's no good way to either debug this with a debugger or log these values for later inspection. With good functional programming constructs, entire methods can be rewritten as single statements like this but there seems to be no good way to inspect intermediate states, even counts (10, 5, 5, 5 here).
What's the best way to debug these?
You can log the intermediate values (lists) with
fun <T> T.log(): T { println(this); this }
//USAGE:
val nums = (10 downTo 1)
.filter { it % 2 == 0 }.log()
.map { it * it }.log()
.sorted().log()
This will work as desired since in your example you work with collections, not sequences. For lazy Sequence you need:
// coming in 1.1
public fun <T> Sequence<T>.onEach(action: (T) -> Unit): Sequence<T> {
return map {
action(it)
it
}
}
fun <T> Sequence<T>.log() = onEach {print(it)}
//USAGE:
val nums = (10 downTo 1).asSequance()
.filter { it % 2 == 0 }
.map { it * it }.log()
.sorted()
.toList()
In latest Intellij Idea when adding a breakpoint you have an option to set it to not inspect whole expression but only a Lambda body.
Then in the debug itself you can see what is happening inside of your Lambda.
But this is not the only way. You can also use Run to cursor (Alt + F9).
I think the current correct answer is that you want the Kotlin Sequence Debugger plugin, which lets you use IntelliJ's lovely Java stream debugger with Kotlin sequences.
Note that (unless I'm doing something wrong) it doesn't appear to work with collections, so you will have to convert the collection to a sequence in order to debug it. Easy enough using Iterable.asSequence, and a small price to pay -- you can always revert that change once you are done debugging.
you may use the also inline function to log, print at any sequence stage as explained by Andrey Breslav at Google I/O '18
(1..10)
.filter { it % 2 == 0 }
.also { e -> println(e) /* do your debug or print here */ }
.map { it * 2 }
.toList()