Unweave sequence, Kotlin functional/streaming idiom - kotlin

I have a sequence of interleaved data (with fixed stride) and I'd like to reduce it to a single value for each "structure" (n*stride values to n values).
I could just use loop writing into the mutable list with selected step for reader index, but I'm looking for more functional and readable approach. Any thoughts?
For example:
Input sequence consists of RGB triplets (stride 3) and output is grayscale.
Imperative way is like:
fun greyscale(stream:List<Byte>):List<Byte>{
val out = ArrayList(stream.size / 3)
var i = 0; var o = 0
while(i < stream.size)
out[o++]=(stream[i++] + stream[i++] + stream[i++])/3
return out
}
How can I make something like that without explicitly implementing a function and mutable container, but purely on functional extensions like .map and so on?

Kotlin 1.2 (Milestone 1 was released yesterday) brings the chunked method on collections. It chunks up the collection into blocks of a given size. You can use this to implement your function:
fun greyscale(stream: List<Byte>): List<Byte> =
stream.chunked(3)
.map { (it.sum() / 3).toByte() }

A possible way would be grouping by the index of the elements (in this case /3) and mapping these groups to their sum.
stream.withIndex()
.groupBy { it.index / 3 }
.toSortedMap()
.values
.map { (it.sumBy { it.value } / 3).toByte() }
Also strictly functional, but using Rx, would be possible by using window(long)
Observable.from(stream)
.window(3)
.concatMap { it.reduce(Int::plus).toObservable() }
.map { (it / 3).toByte() }

Similar to #marstran's answer, in Kotlin 1.2 you can use chunked function, but providing the transform lambda to it:
fun greyscale(stream: List<Byte>): List<Byte> =
stream.chunked(3) { it.average().toByte() }
This variant has an advantage that it doesn't instantiate a new List for every triple, but rather creates a single List and reuses it during the entire operation.

Excludes remaining elements:
const val N = 3
fun greyscale(stream: List<Byte>) = (0 until stream.size / N)
.map { it * N }
.map { stream.subList(it, it + N).sum() / N }
.map(Int::toByte)
Output
[1, 2, 3, 4, 5, 6] => [2, 5]
[1, 2, 3, 4, 5] => [2]
Includes remaining elements:
const val N = 3
fun greyscale(stream: List<Byte>) = (0 until (stream.size + N - 1) / N)
.map { it * N }
.map { stream.subList(it, minOf(stream.size, it + N)).sum() / N }
.map(Int::toByte)
Output
[1, 2, 3, 4, 5, 6] => [2, 5]
[1, 2, 3, 4, 5] => [2, 3]

Best what I'm capable of is this:
fun grayscale(rgb:List<Byte>):List<Byte>
= rgb.foldIndexed(
IntArray(rgb.size / 3),
{ idx, acc, i ->
acc[idx / 3] = acc[idx / 3] + i; acc
}).map{ (it / 3).toByte() }
Output
in: [1, 2, 3, 4, 5, 6]
out: [2, 5]
And variations with ArrayList with add and last

Related

Is there any operation to multiply each element in the first array to each element in the second array in Kotlin?

Is there any function (like fold, map, filter), which gets 2 arrays and lambda-function (for example multiplication) as parameters and returns third array?
I've used cycle for, but is there more beautiful method?
Yes, there is zip (nice example at the bottom of the page), see this (different) example:
fun main() {
val a = arrayOf( 1, 2, 3, 4 )
val b = arrayOf( 1, 2, 3, 4 )
val c = a.zip(b) { i, j -> i * j }
println(c)
}
which outputs
[1, 4, 9, 16]
There isn't a built in specifically but you can do this:
array1.zip(array2).map { (x,y) -> x*y }

Kotlin Array Slice Indexing

Let's say I want to iterate through all but the first element in Kotlin IntArray. Currently, I'm doing it like this:
fun minimalExample(nums: IntArray): Unit {
for(num in nums.sliceArray(IntRange(1,nums.size-1))) println(num)
}
Is there an easy syntax for doing this like in Python (I don't want to have to specify the ending index of the nums array):
for (num in nums[1:])
I think you could use Kotlin's drop which will remove the first n elements of an array.
fun minimalExampleWithDrop(nums: IntArray): Unit {
for(num in nums.drop(1)) println(num)
}
minimalExampleWithDrop(intArrayOf(1,2,3,4,5,6))
// 2
// 3
// 4
// 5
// 6
Repl.it:
https://repl.it/repls/SvelteShadyLivecd
You can alternatively also use the slice method which is present in lists and arrays. Here are examples for both:
val a = listOf(1, 2, 3, 4)
println(a.slice(1..a.size - 1))
val b = arrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
println(b.slice(4..5))
This will print out:
[2, 3, 4]
[5, 6]
A basic for loop with 1 as starting index
val myList = intArrayOf(1,2,3,4,5,6)
for(i in 1 until myList.size){
Log.d(TAG,"${myList[i]}")
}
Or since it's an IntArray you can use it as an Iterator and skip elements like shown here
val iterator = myList.iterator()
// skip an element
if (iterator.hasNext()) {
iterator.next()
}
iterator.forEach {
Log.d(TAG,"it -> $it")
}
Just to add to #gil.fernandes answer, you can use slice with until like this:
val list = arrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
println(list.slice(0 until 5))
This will output:
[0, 1, 2, 3, 4]

Kotlin code - how does FlatMap work here?

The following is code from a LeetCode solution.
This is the description:
Given an array A of non-negative integers, half of the integers in A are odd, and half of the integers are even.
Sort the array so that whenever A[i] is odd, i is odd; and whenever A[i] is even, i is even.
I managed to write code that worked but mine was almost like Java but in Kotlin (a common problem - I know).
I found this code in the comments:
fun sortArrayByParityII(A: IntArray): IntArray {
val even = A.filter { it % 2 == 0 }
val odd = A.filter { it % 2 == 1 }
return even.zip(odd).flatMap { listOf(it.first, it.second) }.toIntArray()
}
I know that the first couple of line do. They simple filter the array into even and odd arrays.
I even understand (after looking up) what the "zip" does.
What I can't figure out is what this does:
flatMap { listOf(it.first, it.second) }
Let's look step by step:
fun main() {
val list = (1..10).toList()
val even = list.filter { it % 2 == 0 } // [2, 4, 6, 8, 10]
val odd = list.filter { it % 2 == 1 } // [1, 3, 5, 7, 9]
val zipped = even.zip(odd) // [(2, 1), (4, 3), (6, 5), (8, 7), (10, 9)]
val flatten = zipped.flatMap { listOf(it.first, it.second) } // [2, 1, 4, 3, 6, 5, 8, 7, 10, 9]
}
flatMap takes a function which returns a list and inserts elements of this list in to initial list. So [(2, 1), (4, 3)] becomes [2, 1, 4, 3]
given the filtered lists:
odd = [1,3,5,7,9,...]
even = [2,4,6,8,...]
the zip function concatenates each single item of each list into a list of tuples:
even.zip(odd)
// [(2,1),(4,3),(6,5),(8,7),...]
flat map here is doing the operation on each item(tuple) and returns a single list, it picks first then second item in each tuple and adds them into a single list:
even.zip(add).flatMap { listOf(it.first, it.second) }
// [2, 1, 4, 3, 6, 5, 8, 7, 10, 9]

Swift enumerated equivalent in Kotlin

In a 3x3 matrix representation, i can find the sum of both diagonals with one liners in Swift as below,
let array = [
[1, 2, 3],
[4, 5, 6],
[-7, 8, 9]
]
let d1 = array.enumerated().map({ $1[$0] }).reduce(0, +)
let d2 = array.reversed().enumerated().map({ $1[$0] }).reduce(0, +)
print(d1) // prints 15
print(d2) // prints 1
I am able to find map and reduce equivalents in Kotlin as flatMap and fold but couldn't find for enumerated.
How can we achieve similar with higher order functions in Kotlin?
Starting with this input:
val input: Array<Array<Int>> = arrayOf(
arrayOf(1, 2, 3),
arrayOf(4, 5, 6),
arrayOf(-7, 8, 9)
)
this is how I'd phrase the diagonal sums:
val mainDiagonalSum = input.indices
.map { input[it][it] }
.reduce(Int::plus)
val counterDiagonalSum = input.indices
.map { input[input.size - 1 - it][it] }
.reduce(Int::plus)
Note that this is an improvement over your solution because it doesn't have to create the reversed array. It improves the time complexity from O(n2) to O(n).
If you're dealing with large matrices, it would pay to reduce the space complexity from O(n) to O(1) as well, by using fold instead of reduce:
val mainDiagonalSum = input.indices
.fold(0) { sum, i -> sum + input[i][i] }
val counterDiagonalSum = input.indices
.fold(0) { sum, i -> sum + input[input.size - 1 - i][i] }
It looks like you're looking for withIndex

Product of a List or Array in Kotlin

I'm trying to find a way to get the product of a List or Array without using "repeat" or any loop on Kotlin but after some research I couldn't find anything similar.
Something like this in Python would be:
>>> reduce(lambda x, y: x*y, [1,2,3,4,5,6])
output: 720
You can use reduce in Kotlin.
From the doc:
Accumulates value starting with the first element and applying
operation from left to right to current accumulator value and each
element.
val list = listOf<Int>(1, 2, 3, 4, 5, 6)
val array = intArrayOf(1, 2, 3, 4, 5, 6)
list.reduce { acc, i -> acc * i } // returns 720
array.reduce { acc, i -> acc * i } // returns 720
An even simpler solution might be: (1..6).reduce(Int::times)
Use the fold function
val total = listOf(1, 2, 3, 4, 5).fold(1, { total, next -> total * next })
Hope this helps:
fun main(args: Array<String>){
val array = intArrayOf(1, 2, 3, 4, 5, 6)
val product = array.fold(1){acc, i -> acc * i}
println("The result is: $product")
}
This will output the product of the array.
Use the fold or reduce function. Both will work.
val array = arrayOf(1, 2, 3, 4, 5, 6)
println("Product of list: ${listOfMultiplication(array)}")
fun listOfMultiplication(array: Array<Int>): Int {
return array.reduce { total, next -> total * next }
}
val array = arrayOf(1, 2, 3, 4, 5, 6)
println("Product of list: ${listOfMultiplication(array)}")
fun listOfMultiplication(array: Array<Int>): Int {
return array.fold(1) { total, next -> total * next }
}