I have a Vec<T> that has elements matching a pattern. I want to remove all trailing instances of the elements that match the pattern.
For example, I have a Vec<i32> and the pattern is (|x| x == 0). If the input was: vec![0, 1, 0, 2, 3, 0, 0], the output should be: vec![0, 1, 0, 2, 3]
To do this I tried:
fn main() {
let mut vec = vec![0, 1, 0, 2, 3, 0, 0];
vec = vec.into_iter().rev().skip_while(|&x| x == 0).rev();
}
But I get these compiler errors:
error[E0277]: the trait bound `std::iter::SkipWhile<std::iter::Rev<std::vec::IntoIter<{integer}>>, [closure#src/main.rs:3:44: 3:55]>: std::iter::DoubleEndedIterator` is not satisfied
--> src/main.rs:3:57
|
3 | vec = vec.into_iter().rev().skip_while(|&x| x == 0).rev();
| ^^^ the trait `std::iter::DoubleEndedIterator` is not implemented for `std::iter::SkipWhile<std::iter::Rev<std::vec::IntoIter<{integer}>>, [closure#src/main.rs:3:44: 3:55]>`
error[E0308]: mismatched types
--> src/main.rs:3:11
|
3 | vec = vec.into_iter().rev().skip_while(|&x| x == 0).rev();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::vec::Vec`, found struct `std::iter::Rev`
|
= note: expected type `std::vec::Vec<{integer}>`
found type `std::iter::Rev<std::iter::SkipWhile<std::iter::Rev<std::vec::IntoIter<{integer}>>, [closure#src/main.rs:3:44: 3:55]>>`
The strange thing is that DoubleEndedIterator is implemented for SkipWhile. In fact, SkipWhile even implements rev(). See here.
What am I doing wrong? Is there a better approach?
The iterator adaptor for reversal only works for iterators which can be traversed from any of the two ends (as in, it is a DoubleEndedIterator). While this is the case for the original one, this is no longer possible from the moment we include skip_while. In order to follow that approach, you would have to collect the rest of the reversed vector, and only then reverse again.
I, on the other hand, would just choose to fetch the index of the first trailing zero and truncate the vector with it.
let mut vec = vec![0, 1, 0, 2, 3, 0, 0];
if let Some(i) = vec.iter().rposition(|x| *x != 0) {
let new_len = i + 1;
vec.truncate(new_len);
}
... or just grab a slice instead:
let piece = &vec[..new_len];
Playground
As the error messages state:
the trait DoubleEndedIterator is not implemented for SkipWhile<...> — Take a look at the implementation of SkipWhile:
pub struct SkipWhile<I, P> {
iter: I,
flag: bool,
predicate: P,
}
You cannot reverse an iterator built from SkipWhile because it has no way of tracking if the "current" item was skipped when you add in the ability to pull from the front and the back.
expected struct Vec, found struct Rev — You still have an iterator, but you are trying to store it where a Vec must be stored. You cannot put a type A where a type B is needed.
I would collect the vector and then reverse it in place:
fn main() {
let mut vec = vec![0, 1, 0, 2, 3, 0, 0];
vec = vec.into_iter().rev().skip_while(|&x| x == 0).collect();
vec.reverse();
println!("{:?}", vec);
assert_eq!(vec, [0, 1, 0, 2, 3]);
}
DoubleEndedIterator is implemented for SkipWhile.
This is not true. If you look at the documentation for SkipWhile, it does not list that it implements DoubleEndedIterator. Here's an example of a trait it does implement: FusedIterator.
In fact, SkipWhile even implements rev()
It doesn't actually. Iterator::rev is only implemented in the condition that Self (which is SkipWhile) implements DoubleEndedIterator, which this doesn't:
fn rev(self) -> Rev<Self>
where
Self: DoubleEndedIterator,
Just to get things started, here is a really dodgy solution:
fn main() {
let mut vec = vec![0, 1, 0, 2, 3, 0, 0];
vec = vec.into_iter().rev().skip_while(|&x| x == 0).collect();
vec = vec.into_iter().rev().collect();
}
Related
I have for example in JS a higher-order function, a function passed to a map:
const numbers = [1, 1, 2, 3, 5, 8]
const transformFunction = x => x + 2
console.log ("transformatio:: ", numbers.map(transformFunction))
If I want to accomplish that in Kotlin, I have:
val numbers = setOf(1, 1, 2, 3, 5, 8)
fun transformFunction (x: Int): Int {
return x + 2
}
println("transformFunction:: ${numbers.map{transformFunction}}")
But Im getting errors:
error: expecting a top level declaration println("transformFunction::
${numbers.map{transformFunction}}")
So what is missing to pass the function to my map operator?
If you pay close attention in that snippet code of js, transformFunction has type function.
So to translate that snippet to Kotlin, declare a variable transformFunction with the type function, too. Then you are good to go
val numbers = setOf(1, 1, 2, 3, 5, 8)
val transformFunction: (Int) -> Int = { it + 2 }
println("transformFunction:: ${numbers.map(transformFunction)}")
The above snippet is the closest translation from JS to Kotlin. But if you want to keep your code the way it is without so many changes, here you are
val numbers = setOf(1, 1, 2, 3, 5, 8)
fun transformFunction (x: Int): Int {
return x + 2
}
println("transformFunction:: ${numbers.map{transformFunction(it)}}")
// or
println("transformFunction:: ${numbers.map(::transformFunction)}")
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 }
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
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
In Ruby, if I had an array a = [1, 2, 3, 4, 5] and I wanted to get the sum of each element times its index I could do
a.each.with_index.inject(0) {|s,(i,j)| s + i*j}
Is there an idiomatic way to do the same thing in Rust? So far, I have
a.into_iter().fold(0, |x, i| x + i)
But that doesn't account for the index, and I can't really figure out a way to get it to account for the index. Is this possible and if so, how?
You can chain it with enumerate:
fn main() {
let a = [1, 2, 3, 4, 5];
let b = a.into_iter().enumerate().fold(0, |s, (i, j)| s + i * j);
println!("{:?}", b); // Prints 40
}