I have an iterator of strings from fieldNames of JsonNode:
val mm = ... //JsonNode
val xs = mm.fieldNames()
I want to loop over the fields while keeping count, something like:
when mm.size() {
1 -> myFunction1(xs[0])
2 -> myFunction2(xs[0], xs[1])
3 -> myFunction3(xs[0], xs[1], xs[2])
else -> print("invalid")
}
Obviously the above code does not work as xs the Iterator cannot be indexed like so. I tried to see if I can convert the iterator to list by mm.toList() but that does not exist.
How can I achieve this?
Probably the easiest way is to convert iterator to Sequence first and then to List:
listOf(1,2,3).iterator().asSequence().toList()
result:
[1, 2, 3]
I would skip the conversion to sequence, because it is only a few lines of code.
fun <T> Iterator<T>.toList(): List<T> =
ArrayList<T>().apply {
while (hasNext())
this += next()
}
Update:
Please keep in mind though, that appending to an ArrayList is not that performant, so for longer lists, you are better off with the following, or with the accepted answer:
fun <T> Iterator<T>.toList(): List<T> =
LinkedList<T>().apply {
while (hasNext())
this += next()
}.toMutableList()
You can turn an Iterator into an Iterable using Iterable { iterator } on which you can then call toList():
Iterable { listOf(1,2,3).iterator() }.toList() // [1, 2, 3]
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.
Is there a convenient way in Kotlin to iterate through an array, let's say IntArray, in reversed order with these 2 conditions:
do not create an additional reversed copy of the array.
I need a handle to an element like in Java's enhanced for.
The best I could get is adding an extension function, but this needs to be done for each type of array if I need it not only for IntArrays:
fun IntArray.forEachReversed(action: (Int) -> Unit): Unit {
for (i in indices.reversed()) action(this[i])
}
Is there a better way in Kotlin class library?
this needs to be done for each type of array if I need it not only for IntArrays:
I think this is unavoidable because of the way the JVM works. There are separate classes to represent each primitive type on the JVM. However, there are only 8 of them, so it shouldn't be too bad ;-)
For Collections, there is the asReversed() function, but it's not available for arrays:
val original = mutableListOf('a', 'b', 'c', 'd', 'e')
val originalReadOnly = original as List<Char>
val reversed = originalReadOnly.asReversed()
println(original) // [a, b, c, d, e]
println(reversed) // [e, d, c, b, a]
// changing the original list affects its reversed view
original.add('f')
println(original) // [a, b, c, d, e, f]
println(reversed) // [f, e, d, c, b, a]
To answer you question, you solution looks fine but if your are targeting primitive IntArray, LongArray, FloatArray etc you cannot come with a generic solution, as this classes are independent and only thing common is Iterator, but you cannot traverse the iterator in reverse order without making a copy(ListIterator supports reverse iteration though), but the closest you can get is to use Array<T> instead specific Array like below
fun <T> Array<T>.forEachReversed(action: (T) -> Unit){
for(i in indices.reversed()){ action(this[i]) }
}
val intArray = Array(2){ 0 }
val longArray = Array<Long>(2){ 0 }
intArray.forEachReversed { }
longArray.forEachReversed { }
As pointed out by #ajan.kali if you need primitive arrays there is not much you can do. I suppose you have to deal with arrays but, if this is not the case, you should prefer other data structures (more info here)
Returning to your question, if your are fine using generic arrays you could probably declare your iterator to iterate in reverse order:
class ReverseIterator<T>(val it: Iterable<T>) : Iterator<T> {
private var index = it.count() - 1
override fun hasNext() = index >= 0
override fun next(): T = try { it.elementAt(index--) } catch (e:
IndexOutOfBoundsException) { index -= 1; throw
NoSuchElementException(e.message) }
}
then your extension function will become:
fun <T> Iterable<T>.forEachReversed(action: (T) -> Unit) {
for(elem in ReverseIterator(this)) {
action(elem)
}
}
and then given an array you can invoke it this way:
intArrayOf(1, 2, 3).asIterable().forEachReversed {
println(it)
}
Not particularly happy with this, but with arrays there is not much you can do other to try avoiding them.
I have the following data for my task:
Input: nums = [1,2,3,4]
Output: [1,3,6,10]
Explanation: Running sum is obtained as follows: [1, 1+2, 1+2+3, 1+2+3+4].
As u see, I need to return IntArray, the first thing I used was runningReduce() , but this function is used in the version of Kotlin 1.4.30.
fun runningSum(nums: IntArray): IntArray {
return nums.runningReduce { sum, element -> sum + element }.toIntArray()
}
Yes, this solution works, but how can I solve the same problem using reduce() or fold()?
Try the following:
nums.fold(listOf(0)) { acc, i -> acc + (acc.last() + i) }.drop(1).toIntArray()
The solution is sub-optimal though: it copies the list in each iteration. But looks fancy.
To avoid copying, you could write it as follows:
nums.fold(mutableListOf(0)) { acc, i -> acc += (acc.last() + i); acc }.drop(1).toIntArray()
I think I prefer the first version, the second one is not pure from functional perspective.
Mafor is right, fold() is not a good choice when producing a collection because it copies the collection every time so you need to workaround with mutable collections, which defeats the point of the functional style.
If you really want to work with arrays, which are mutable, doing it the old fashioned procedural way may be best:
val array = intArrayOf(1, 2, 3, 4)
for (i in array.indices.drop(1)) {
array[i] += array[i - 1]
}
println(array.joinToString(", "))
Here's a slightly modified version of Mafor's answer that gives you an IntArray and avoids the use of multiple statements - it still uses the mutable list though:
val input = intArrayOf(1, 2, 3, 4)
val output = input.fold(mutableListOf(0)) { acc, cur ->
acc.apply { add(last() + cur) }
}.drop(1).toIntArray()
println(output.joinToString(", "))
Both of these print 1, 3, 6, 10.
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
}
I need to iterate part of an array backwards. I'd like to do that "functionally" as it's more comprehensible, like that
for (b in buf.sliceArray(0 until bufLimit).reversedArray()) {}
But both sliceArray and reversedArray are not lazy. Is there a lazy version or should I probably fall back to
for (bIdx in bufLimit - 1 downTo 0) {
val b = buf[bIdx]
}
which is more confusing and verbose?
If you use a list instead of an array, then you can reverse it and then convert to a Sequence:
val buf: List = listOf(1, 2, 3, 4, 5)
val bufLimit = 3
for (b in buf.asReversed().asSequence().drop(buf.size - bufLimit)) {
println(b)
}
Functions with the as prefix only wrap objects without copying, so the code above does not copy the buf content.
Note that you shouldn't loose any performance compared to Array if you use an ArrayList.
However this solution does involve several iterators, so it is somewhat less efficient than the index code you have suggested in the question:
for (bIdx in bufLimit - 1 downTo 0) {
val b = buf[bIdx]
}
I suggest creating an extension function to handle your specific use case. e.g.:
/**
* Performs the given [action] on each element at the specified [indices].
*/
inline fun ByteArray.forEachAt(indices: Iterable<Int>, action: (Byte) -> Unit): Unit {
indices.forEach { index -> action(this[index]) }
}
Usage:
buf.forEachAt((0 until bufLimit).reversed)) {}
// or
buf.forEachAt(bufLimit - 1 downTo 0) {}