I'm trying to modify the `IntRange` using `onEach...
# announcements
d
I'm trying to modify the
IntRange
using
onEach
function like this
Copy code
val range = (1..3).onEach { it + 1}
println(range) // expecting 2..4 but still getting 1..3
So what should I try?
t
onEach
is mainly used fore side effects triggered on each element, but doesn't change anything. Use
map
in your case
4
c
It will be clear why if you look at the signature of onEach: its parameter is
(T) -> Unit
, which means it ignores whatever you give to it
👍 4
d
map
returns
List
but I want
IntRange
t
there is no way to create a new range that way
d
Lol, I guess I'll continue with this code
Copy code
val range = 1..3
val modifiedRange = range.first..range.last
t
yup, you can write this function yourself of course, like so https://pl.kotl.in/Al6-Q2ImR
👍 1
d
Cool. Thanks a lot 🙌
c
That implementation might not always work
For example:
Copy code
val r = -5..5
val g = r.mapNewRange { abs(it) }
t
works on my machine 😄
5..5 is a perfectly valid IntRange
d
@CLOVIS I think that use case is not valid for my code. I know in my application
IntRange
will never have negative value
But thanks for pointing out
c
@thana it is a legal IntRange, but that's not what the function should do (
map
shouldn't change the size of the functor)
t
ok
while that's not wrong, i think is quite an academic question in this case
e
Copy code
val r = 0..Int.MAX_VALUE
val g = r.mapNewRange { it + 1 }
is also broken. that extension only works if the function is monotonically increasing
t
lol
c
@Danish Ansari it's not about negative numbers, it's about non-bijections:
Copy code
// Size: 6
val r = 0..5

// Size: 6 (0, 1, 0, 1, 0, 1)
val l = r.map { it % 2 }

// Size: 2 (0, 1)
val g = r.mapNewRange { it % 2 }
t
@ephemient no thats pretty useless to point out
e
to give another non-overflowing example:
Copy code
val r = 0..5
val l = r.map { it % 4 }
val g = r.mapNewRange { it % 4 }
even if you sort
l
back into a range, it still contains more elements than
g
c
I just wish the standard library returned an
Iterator
or
Sequence
instead of a
List
t
@ephemient by the same token you could claim that
+
is broken
d
I'm pretty speechless at this point 😅
t
me too
e
arguably, a non-injective function can make some sort of sense, e.g.
r.map { it / 2 }.toSet().size == r.mapNewRange { it / 2 }.size
c
It should probably be called something else then,
map
should never have an impact on the size
e
.mapTo(mutableSetOf()) { it / 2 }
can change the size, but yeah I agree this case should definitely not be called "map"
long discussion of similar extensions here: https://kotlinlang.slack.com/archives/C0B8Q383C/p1625175187058900
c
Essentially, that implementation works only if your lambda is a bijection (= for a specific output, there is only a single input) `it + 1`: if the result is 2, the input must have been 1, so that's good (I'm ignoring overflows here) `it % 2`: if the result is 0, the input could have been any even integer, so that's bad `it * it`: if the result is 25, the input could have been -5 or 5, so that's bad If you're completely sure you will only have bijections, feel free to use that function. If you ever forget that precondition though... The results will be weird
e
*monotonically increasing injections, it's also broken for
{ -it }
which in effect only permits constant offsets
c
Ah, it could be fixed by reversing the
step
, but yeah that's very limiting
z
I just wish the standard library returned an
Iterator
or
Sequence
instead of a
List
It kind of does -
List
implements
Iterable
so you can get an
Iterator
from it - I don’t see how that solves this problem though.
d
Wouldn’t even doing it * 2 result in a range that’s larger than the original? Unless the step is also changed. I’d probably just make functions for shiftByAdding and shiftBySubtracting (if needed) and then your size doesn’t change and each one should only need to test for max and min values not being crossed. Similar can be done with multiplying provided the step is adjusted accordingly for the progression. Division seems tougher because you’d need to consider the step, the first and the last element of the range and whether division makes sense for the use case
I.e., in your example you only wanted to move the entire range over by exactly one so taking an arbitrary lambda to transform Int to Int gives too much freedom
e
@thana anyway
+
is not broken, it's always well-defined. it's just not monotonic across its entire range of inputs
t
@ephemient gosh! keep me out of this frutless discussion, please