The problem of different result values ​due to capturing in Kotlin sequence - kotlin

If a value called prime is declared externally in the problem code, Capturing occurs, resulting in different results. Can someone tell me in detail why the result value is different when capturing occurs?
normal code
val primes: Sequence<Int> = sequence {
var numbers = generateSequence(2) { it + 1 }
while (true) {
val prime = numbers.first()
yield(prime)
numbers = numbers.drop(1)
.filter {
it % prime != 0
}
}
}
println(primes.take(10).toList()) // [2, 3, 5, 7. 11, 13, 17, 19, 23, 29]
problem code
val primes: Sequence<Int> = sequence {
var numbers = generateSequence(2) { it + 1 }
var prime: Int
while (true) {
prime = numbers.first()
yield(prime)
numbers = numbers.drop(1)
.filter {
it % prime != 0
}
}
}
println(primes.take(10).toList()) // [2, 3, 5, 6, 7, 8, 9, 10, 11, 12]
Lambda capture occurs when using sequences

When you call the method filter { it % prime != 0 } you permanently attach one filter, with its lambda function, to the numbers Sequence object. The value of prime in that lambda is captured from the enclosing code. With each loop, more and more filters are attached to the numbers Sequence.
In the first (working) example, each time a filter lambda is attached to the numbers Sequence, it gets its own unique version of the prime variable. Specifically, it gets the unique val prime that is defined at the start of the while loop in which that filter lambda is attached. That's just what you want.
In the second (broken) example, there is only one prime variable throughout the program: the var prime defined outside the loop. It changes every time the while loop runs. That means that every filter lambda is identical at any point in time: they all use the same prime value, being the last number taken off the front of the (chopped) numbers sequence. And prime keeps going up by one with each iteration. All in all, it means with each loop all the identical filter lambda functions also change and so have no discernible effect on the numbers sequence, or in turn the sequence printed to the screen.

Because the filter method is evaluated lazily, every iteration of the loop again and again. In the first code block, you define prime locally so that's what's captured. In the second block, it knows prime is reassigned every time, so it'll only look at the latest value.

Related

Kotlin - How to apply modulo operation on each element of a matrix?

I find Lambda in Kotlin to be very confusing and on the top of it is "it".
There are two things I know about "it" and i.e.
If your Lambda has their own argument, you can replace its name with "it".
"It" is an automatically generated name for your Lambda, if it has
only one argument, and you don't specify a different argument name.
Still I don't understand what actually passes as "it".
For E.g. I wanted to apply modulo function on each element of a 3x3 matrix.
fun main(){
var result = Array(3) {
IntArray(3) { 3;2;4;6;7;9;12;11;23 }
}
result = Array(3){ IntArray(3) {it%2} }
println(result.joinToString("\n") { it.joinToString(" ") })
}
Here I assumed that "it" takes each element of the matrix which is clearly not the case as my output was:
0 1 0
0 1 0
0 1 0
So can you please explain me how "it" works, what is happening here? and what would be the correct way to implement this program?
Your line
result = Array(3){ IntArray(3) {it%2} }
isn't doing anything to the original Array that result is pointing at. You are creating a brand new group of array objects by calling the Array and IntArray constructors.
The lambda that you pass to the IntArray constructor has an input parameter that represents the array index, and the return value of your lambda is what will be put into the array at that index. So in this case it is the array index, and your lambda is returning 0 and 1 for even and odd indices respectively.
You are also instantiating your array incorrectly to begin with. Your lambda that you pass to that IntArray constructor is throwing away a bunch of pointless Int values and then returning 23 for each item. So you've created a 3x3 matrix that is completely filled with the number 23.
The correct syntax for creating an array with explicit values is to use arrayOf or intArrayOf.
val result = arrayOf(
intArrayOf(3, 2, 4),
intArrayOf(6, 7, 9),
intArrayOf(12, 11, 23)
)
To modify all the values of an array, you typically iterate the traditional way, not with a lambda:
for (innerArray in result) {
for (i in innerArray.indices)
innerArray[i] = innerArray[i] % 2
}
You were probably thinking of the map function, which lets you pass a lambda and returns a new List with the lambda function applied to every element of the input collection. Or when working with collections other than arrays, you can use forEach or onEach to iterate them without modifying 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 problem with understanding piece of code

I've just started learning programming and I'm having a problem understanding a piece of code from a tutorial. Could anyone explain what the Kotlin code below does?
Thank you
fun f(i:Int, list:MutableList<Int>) : Boolean {
for (number in list) {
if (i % number == 0) {
return false
}
}
return true
}
fun main(args:Array<String>) {
val result = mutableListOf<Int>()
for (number in 2..100) {
if (f(number, result)) {
result.append(number)
}
print(result.joinToString())
}
The main method creates a new list of integers. In a loop from 2 to 200 it calls the function f with current number of the loop (number) and the list created.
The function checks if the number handed over can be divided by any number in the list. In case it can be divided, false is returned, else true.
If the number couldn't be divided then the number is stored inside the list.
So it is a simple algorithm to find prime numbers. The list stores all so far found prime numbers. And the function checks if the number can be divided by any of the prime numbers.
f(...) checks whether i divides with any number in the list - if so, returns false.
main(..) loops through all numbers from 2..100 and adds numbers that don't divide with any number previously added to the list.
Basically, it will print all prime numbers between 2..100

Difference between fold and reduce in Kotlin, When to use which?

I am pretty confused with both functions fold() and reduce() in Kotlin, can anyone give me a concrete example that distinguishes both of them?
fold takes an initial value, and the first invocation of the lambda you pass to it will receive that initial value and the first element of the collection as parameters.
For example, take the following code that calculates the sum of a list of integers:
listOf(1, 2, 3).fold(0) { sum, element -> sum + element }
The first call to the lambda will be with parameters 0 and 1.
Having the ability to pass in an initial value is useful if you have to provide some sort of default value or parameter for your operation. For example, if you were looking for the maximum value inside a list, but for some reason want to return at least 10, you could do the following:
listOf(1, 6, 4).fold(10) { max, element ->
if (element > max) element else max
}
reduce doesn't take an initial value, but instead starts with the first element of the collection as the accumulator (called sum in the following example).
For example, let's do a sum of integers again:
listOf(1, 2, 3).reduce { sum, element -> sum + element }
The first call to the lambda here will be with parameters 1 and 2.
You can use reduce when your operation does not depend on any values other than those in the collection you're applying it to.
The major functional difference I would call out (which is mentioned in the comments on the other answer, but may be hard to understand) is that reduce will throw an exception if performed on an empty collection.
listOf<Int>().reduce { x, y -> x + y }
// java.lang.UnsupportedOperationException: Empty collection can't be reduced.
This is because .reduce doesn't know what value to return in the event of "no data".
Contrast this with .fold, which requires you to provide a "starting value", which will be the default value in the event of an empty collection:
val result = listOf<Int>().fold(0) { x, y -> x + y }
assertEquals(0, result)
So, even if you don't want to aggregate your collection down to a single element of a different (non-related) type (which only .fold will let you do), if your starting collection may be empty then you must either check your collection size first and then .reduce, or just use .fold
val collection: List<Int> = // collection of unknown size
val result1 = if (collection.isEmpty()) 0
else collection.reduce { x, y -> x + y }
val result2 = collection.fold(0) { x, y -> x + y }
assertEquals(result1, result2)
Another difference that none of the other answers mentioned is the following:
The result of a reduce operation will always be of the same type (or a super type) as the data that is being reduced.
We can see that from the definition of the reduce method:
public inline fun <S, T : S> Iterable<T>.reduce(operation: (acc: S, T) -> S): S {
val iterator = this.iterator()
if (!iterator.hasNext()) throw UnsupportedOperationException("Empty collection can't be reduced.")
var accumulator: S = iterator.next()
while (iterator.hasNext()) {
accumulator = operation(accumulator, iterator.next())
}
return accumulator
}
On the other hand, the result of a fold operation can be anything, because there are no restrictions when it comes to setting up the initial value.
So, for example, let us say that we have a string that contains letters and digits. We want to calculate the sum of all the digits.
We can easily do that with fold:
val string = "1a2b3"
val result: Int = string.fold(0, { currentSum: Int, char: Char ->
if (char.isDigit())
currentSum + Character.getNumericValue(char)
else currentSum
})
//result is equal to 6
reduce - The reduce() method transforms a given collection into a single result.
val numbers: List<Int> = listOf(1, 2, 3)
val sum: Int = numbers.reduce { acc, next -> acc + next }
//sum is 6 now.
fold - What would happen in the previous case of an empty list? Actually, there’s no right value to return, so reduce() throws a RuntimeException
In this case, fold is a handy tool. You can put an initial value by it -
val sum: Int = numbers.fold(0, { acc, next -> acc + next })
Here, we’ve provided initial value. In contrast, to reduce(), if the collection is empty, the initial value will be returned which will prevent you from the RuntimeException.
Simple Answer
Result of both reduce and fold is "a list of items will be transformed into a single item".
In case of fold,we provide 1 extra parameter apart from list but in case of reduce,only items in list will be considered.
Fold
listOf("AC","Fridge").fold("stabilizer") { freeGift, itemBought -> freeGift + itemBought }
//output: stabilizerACFridge
In above case,think as AC,fridge bought from store & they give stabilizer as gift(this will be the parameter passed in the fold).so,you get all 3 items together.Please note that freeGift will be available only once i.e for the first iteration.
Reduce
In case of reduce,we get items in list as parameters and can perform required transformations on it.
listOf("AC","Fridge").reduce { itemBought1, itemBought2 -> itemBought1 + itemBought2 }
//output: ACFridge
The difference between the two functions is that fold() takes an initial value and uses it as the accumulated value on the first step, whereas the first step of reduce() uses the first and the second elements as operation arguments on the first step.

Counter as variable in for-in-loops

When normally using a for-in-loop, the counter (in this case number) is a constant in each iteration:
for number in 1...10 {
// do something
}
This means I cannot change number in the loop:
for number in 1...10 {
if number == 5 {
++number
}
}
// doesn't compile, since the prefix operator '++' can't be performed on the constant 'number'
Is there a way to declare number as a variable, without declaring it before the loop, or using a normal for-loop (with initialization, condition and increment)?
To understand why i can’t be mutable involves knowing what for…in is shorthand for. for i in 0..<10 is expanded by the compiler to the following:
var g = (0..<10).generate()
while let i = g.next() {
// use i
}
Every time around the loop, i is a freshly declared variable, the value of unwrapping the next result from calling next on the generator.
Now, that while can be written like this:
while var i = g.next() {
// here you _can_ increment i:
if i == 5 { ++i }
}
but of course, it wouldn’t help – g.next() is still going to generate a 5 next time around the loop. The increment in the body was pointless.
Presumably for this reason, for…in doesn’t support the same var syntax for declaring it’s loop counter – it would be very confusing if you didn’t realize how it worked.
(unlike with where, where you can see what is going on – the var functionality is occasionally useful, similarly to how func f(var i) can be).
If what you want is to skip certain iterations of the loop, your better bet (without resorting to C-style for or while) is to use a generator that skips the relevant values:
// iterate over every other integer
for i in 0.stride(to: 10, by: 2) { print(i) }
// skip a specific number
for i in (0..<10).filter({ $0 != 5 }) { print(i) }
let a = ["one","two","three","four"]
// ok so this one’s a bit convoluted...
let everyOther = a.enumerate().filter { $0.0 % 2 == 0 }.map { $0.1 }.lazy
for s in everyOther {
print(s)
}
The answer is "no", and that's a good thing. Otherwise, a grossly confusing behavior like this would be possible:
for number in 1...10 {
if number == 5 {
// This does not work
number = 5000
}
println(number)
}
Imagine the confusion of someone looking at the number 5000 in the output of a loop that is supposedly bound to a range of 1 though 10, inclusive.
Moreover, what would Swift pick as the next value of 5000? Should it stop? Should it continue to the next number in the range before the assignment? Should it throw an exception on out-of-range assignment? All three choices have some validity to them, so there is no clear winner.
To avoid situations like that, Swift designers made loop variables in range loops immutable.
Update Swift 5
for var i in 0...10 {
print(i)
i+=1
}