How I can return IntArray with reduce or fold? - kotlin

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.

Related

Is there an easy way to multiply each element with each other in array / list - Kotlin?

I have got {1,2,3} / or it might be a list<Int> is there an easy way to multiply each element with each other like 1*2 , 1*3, 2*3 ?
This should work, given that you probably don't want to include the duplicates like items[i] * items[j] and items[j] * items[i]
val items = listOf(1, 2, 3, 4)
val result = items.flatMapIndexed { index, a ->
items.subList(index + 1, items.size).map { b -> a * b }
}
println(result) // [2, 3, 4, 6, 8, 12]
flatMapIndexed builds a list for each of the items elements by evaluating the lambda on the index and the item, and then concatenates the lists.
subList is an efficient way to take the items in the specific range: starting at the next index, and until the end of the list.
You can try the old-fashioned way: nested loops
fun main(args: Array<String>) {
val list = listOf( 1, 2, 3 )
for (i in list.indices) {
for (j in (i + 1) until list.size) {
println("${list[i]} * ${list[j]} = ${list[i] * list[j]}")
}
}
}
Output of this code:
1 * 2 = 2
1 * 3 = 3
2 * 3 = 6
If you did want all the permutations (every possible ordering), you could do something like this:
val result = with(items) {
flatMapIndexed { i, first ->
slice(indices - i).map { second -> // combine first and second here }
}
}
slice lets you provide a list of indices for the elements you want to pull, so you can easily exclude the current index and get all the other elements to combo it with. Takes an IntRange too, so you can do slice(i+1 until size) to get the combination (every pairing) functionality too.
Not as efficient as hotkey's subList version (since that doesn't make a copy) but you can get two behaviours this way so I thought I'd mention it! But if I were making a reusable function rather than a quick one-liner, I'd probably go with deHaar's approach with the nested for loops, it's efficient and easy enough to tweak for either behaviour

Idiomatically group String (count consecutively repeated characters)

How with what idioms do I achieve the desired effect?
val input = "aaaabbbcca"
val result = input.(here do the transformations)
val output = listOf("a" to 4, "b" to 3, "c" to 2, "a" to 1)
assert(result == output)
Here's a fun way to do it immutably using fold
fun main() {
val result = "aaaabbbcca"
.chunked(1)
.fold(emptyList<Pair<String, Int>>()) { list, current ->
val (prev, count) = list.lastOrNull() ?: Pair(current, 0)
if (prev == current) list.dropLast(1) + Pair(current, count + 1)
else list + Pair(current, 1)
}
val output = listOf("a" to 4, "b" to 3, "c" to 2, "a" to 1)
check(result == output)
println(result)
}
Output:
[(a, 4), (b, 3), (c, 2), (a, 1)]
This is a tricky little problem, and I can't find a particular idiomatic solution.
However, here's one that's quite concise:
val result = input.replace(Regex("(.)(?!\\1)(.)"), "$1§$2")
.split("§")
.map{ Pair(it[0], it.length) }
It uses a complicated little regex to insert a marker character (§ here, though of course it would work with any character that can't be in the input) between every pair of different characters.  ((?…) is a zero-width look-ahead assertion, so (?!\1) asserts that the next character is different from the previous one.  We need to include the next character in the match, otherwise it'll append a marker after the last character too.)
That gives aaaa§bbb§cc§a in this case.
We then split the string at the marker, giving a list of character groups (in this case "aaaa", "bbb", "cc", "a"), which it's easy to convert into (character,length) pairs.
Using a regex is not always a good solution, especially when it's complicated and unintuitive like this one.  So this might not be a good choice in production code.  On the other hand, a solution using fold() or reduce() probably wouldn't be that much easier to read, either.  In fact, the most maintainable solution might be the old-fashioned one of looping over the characters…
I believe there are no good (efficient, readable) idiomatic ways to solve this. We can use a good, old and boring loop approach. To make it at least a little more funny, we can do it with a lazy computing, utilizing coroutines:
fun String.countConsecutive() = sequence {
if (isEmpty()) return#sequence
val it = iterator()
var curr = it.next()
var count = 1
it.forEach {
if (curr == it) {
count++
} else {
yield(curr.toString() to count)
curr = it
count = 1
}
}
yield(curr.toString() to count)
}
This is good if our string is very long and we only need to iterate over consecutive groups. Even better if we don't need to iterate over all of them.

Compare value against two values with 'or' operator

I have a simple if () condition which needs to check if value is either 1 or 2 (for example). Let's say the value we are comparing against is not 'simple':
if(it.first().property.value == 1 || it.first().property.value == 2) {
// Do stuff
}
Is there a better way to perform this check (without typing the entire expression to get the actual value twice)? The only thing that comes to mind is
if(listOf(1, 2).contains(it.first().property.value)) {
// Do stuff
}
But I'm afraid it's more memory consuming since it has additional list introduced.
Your last suggestion is a good one in general, though it's usually better to use a predefined list (and the in operator):
// At the top level, or in a (companion) object:
val acceptableValues = listOf(1, 2)
// Then in the relevant part of the code:
if (it.first().property.value in acceptableValues)
// Do stuff
That only allocates the list once, and performance is about as good as any other option.  It's also very readable, and general.
(If the list doesn't naturally fit into a named property, you'd have to judge how often it might be needed, in order to trade a minor performance benefit against the conciseness of putting it directly in the condition.)
In fact, because you're looking for consecutive integers, there's a more concise option for this particular test:
if (it.first().property.value in 1..2)
// Do stuff
That would work whenever the acceptable values form an (uninterrupted) range.
Alternatively, if you're always checking against exactly two values, you could write a simple extension function:
fun <T> T.isEither(a: T, b: T) = this == a || this == b
(You could write a more general one using a vararg param, but that would create an array each time — very similar to the in listOf() case we started with.)
You can decide it using a when expression like in this example:
fun main() {
val number = 22
when (number) {
1, 2 -> println("${number} is 1 or 2")
in 10..20 -> println("${number} is between 10 and 20 (inclusively)")
else -> println("${number} is either negative, equals 0, 3, 4, 5, 6, 7, 8, 9, 21 or any number above")
}
}
The output here is
22 is either negative, equals 0, 3, 4, 5, 6, 7, 8, 9, 21 or any number above
You could define an extension function on the type of it to make it more readable:
if(it.isOneOrTwo()) {
// Do stuff
}
Not sure what's the type of your it, replace TYPEOFIT accordingly:
private inline fun TYPEOFIT.isOneOrTwo() = first().property.value == 1 || first().property.value == 2
To additionally improve the condition you could leverage when:
private inline fun TYPEOFIT.isOneOrTwo() = when(first().property.value) {
1,2 -> true
else -> false
}

Kotlin lazy slice array

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) {}

Kotlin sequence concatenation

val seq1 = sequenceOf(1, 2, 3)
val seq2 = sequenceOf(5, 6, 7)
sequenceOf(seq1, seq2).flatten().forEach { ... }
That's how I'm doing sequence concatenation but I'm worrying that it's actually copying elements, whereas all I need is an iterator that uses elements from the iterables (seq1, seq2) I gave it.
Is there such a function?
Your code doesn't copy the sequence elements, and sequenceOf(seq1, seq2).flatten() actually does what you want: it generates a sequence that takes items first from seq1 and then, when seq1 finishes, from seq2.
Also, operator + is implemented in exactly this way, so you can just use it:
(seq1 + seq2).forEach { ... }
The source of the operator is as expected:
public operator fun <T> Sequence<T>.plus(elements: Sequence<T>): Sequence<T> {
return sequenceOf(this, elements).flatten()
}
You can take a look at the implementation of .flatten() in stdlib that uses FlatteningSequence, which actually switches over the original sequences' iterators. The implementation can change over time, but Sequence is intended to be as lazy as possible, so you can expect it to behave in a similar way.
Example:
val a = generateSequence(0) { it + 1 }
val b = sequenceOf(1, 2, 3)
(a + b).take(3).forEach { println(it) }
Here, copying the first sequence can never succeed since it's infinite, and iterating over (a + b) takes items one by one from a.
Note, however, that .flatten() is implemented in a different way for Iterable, and it does copy the elements. Find more about the differences between Iterable and Sequence here.
Something else you might need to do is create a sequence of sequences:
val xs = sequence {
yield(1)
yield(2)
}
val twoXs = sequence {
yieldAll(xs)
// ... interesting things here ...
yieldAll(xs)
}
This doesn't do anything that xs + xs doesn't do, but it gives you a place to do more complex things.