collection class question: If I have a list of var...
# announcements
t
collection class question: If I have a list of varying lengths of positive and negative integers how can I sum the sections w/ the same sign? example
[-1,-1,-1,1,1,-1,-1]
should yield
[-3,2,-2]
I can't figure out how to do this w/o iterating over the list, and keeping a bunch of mutable state. Is there fancy sequence of collection functions I could use to do this?
e
b
kudos, but... madness!
a
https://pl.kotl.in/dg0L-27cL
Copy code
fun List<Int>.accumulatedSigns(): List<Int> = sequence {
    var tempSum = first()
    for (element in asSequence().drop(1)) {
        if(element.sign == tempSum.sign) {
            tempSum += element
        } else {
            yield(tempSum)
            tempSum = element
        }
    }
    yield(tempSum)
}.toList()
e
if you benchmark, you'll find that Sequence has a noticeable fixed cost. if you're going to bother doing it statefully, this would be safer and faster.
t
runningReduce
is a new one for me....
the sequence is nice as well. I didn't know you could use it on lists they are already created. I thought it just created things. neat.
and I know nothing about buildList either.
tons to learn about! thanks so much!
a
BuildList is definitely the way to go, but it is still experimental.
@ephemient I did the benchmark and found that for large lists the sequence solution becomes much better in performance. Since the performance would only matter for large list, I would go for a sequence solution in a general case.
t
what does "large" mean? 100k? 1M?
e
I'm curious, as I ran a benchmark on a list of size 10k and found that the buildList version was faster than sequence by a factor of ~3-4x
t
after some review : I'm not sure I like either the sequence or the buildList. It seems like it's just taking the normal itterative code and dropping it inside something else (a seqeunce or a buildList). Both use mutable state, etc....
I mean, I guess they are better than a while loop, and they do fit in the collection framework... which is what I asked for. But... .I dunno.
b
I'm only a fan of the functional magic when I can take a step back and say, yeah, that's both better and simpler. A lot of times, it's not simpler, just shorter, in an almost code-golf way.
That said, the incredible set of functional data collections + functional magic that comes packaged with Kotlin's standard lib is amazing
t
@byron I think I felt the same as you when I starting using all the functional stuff. But now that I'm used to reading and parsing it, I think it is more helpful and clear than not. This might be the exception when maybe just looping would be easier to understand and maintain. But I'm more curious about this as a learning opportunity than actual production code value.
I find that when I have to iterate over something and keep anything beyond the most simple state, the FP stuff gets overly complex quickly.
I've always wanted something like
mapWithState
where the state itself doesn't end up part of the resulting list.
e
.reduce()
and its more general cousin
.fold()
(and the variants
.runningReduce()
and
.runningFold()
(with alias
.scan()
)) carry over one piece of state as they iterate over each element
t
@ephemient but in all those, the "state" ends in the resulting list. So I need to make a pair() w/ the state and the new element, then map at the end to strip out the now useless state.
e
makes sense, as a functional building block
t
I want to pass along a state that's totally unrelated to the list element. a good example is I want to make ever string is a list unique. So my state is a set of strings that I've seen to date. At each element I want to see if the current elmeent is already in the set, and if so append something to make it unique.
the set/state has nothing to do w/ the resulting list.
e
in Kotlin you'd just use mutable state outside of the flow
t
yeah. that's what I end up doing. I'm just curious if there is a more FP way to do it, and not have mutable state and/or do it in the collection classes.
e
Untitled
you could fold with
Set
as an accumulator, but adding to it will make the whole operation O(n^2) so that's not good
t
that looks good to me... but I've never seen this syntax before.
e
which syntax?
t
the
sequence {
I'm not quite sure what
this
has all in it 🙂
v
@ephemient it’s better for newbies in Kotlin to show your code as :
Copy code
@ExperimentalStdlibApi
fun Iterable<Int>.accumulatedSigns(): List<Int> = buildList {
    val iterator = this@accumulatedSigns.iterator()
    println("iterator ${iterator.hasNext()}")
    if (!iterator.hasNext())
        return@buildList

    var sum = iterator.next()
    for (x in iterator) {
        if (x.sign != sum.sign) {
            add(sum)
            sum = x
        } else {
            sum += x
        }
    }
    add(sum)
}