You could do it in linear time, using fold, both m...
# announcements
a
You could do it in linear time, using fold, both more efficient, and more Kotlinly!:
Copy code
fun List<Int>.maxSubListSum(n: Int) =
    take(n)
        .sum()
        .let { sum ->
            drop(n)
                .foldIndexed(sum to sum) { i, (sum, max), next ->
                    (sum + next - this[i]).let {
                        it to if (it > max) it else max
                    }
                }.second
        }
(Sorry for no thread).
👍 1
Alternative using only fold, looks a bit cleaner:
Copy code
fun List<Int>.maxSubListSum(n: Int) =
    foldIndexed(0 to 0) { i, (sum, max), next ->
        (sum + next - (getOrNull(i - n) ?: 0)).let {
            it to if (it > max) it else max
        }
    }.second
Iterable and Sequence versions...
Copy code
fun Iterable<Int>.maxSubListSum(n: Int) = asSequence().maxSubListSum(n)

fun Sequence<Int>.maxSubListSum(n: Int) =
    zip(IntArray(n).asSequence() + this)
        .fold(0 to 0) { (sum, max), (next, prev) ->
            (sum + next - prev).let {
                it to if (it > max) it else max
            }
        }.second
d
That's cool and all but it became unreadable, to me at least
Oh right you're shifting the sum, that's definitely cool
+1
A comment just might help a bit
l
Explicit return type would make the code more readable.
a
"That's cool and all but it became unreadable, to me at least" But isn't that the goal of Kotlin? One line, no vars 😛
d
😂
You are joking right
a
"Explicit return type would make the code more readable." Maybe, and or just turn on hints in your IDE. What it might benefit from is a name for the
it
and maybe using `max()`:
Copy code
(sum + next - prev).let { newSum ->
                newSum to max(max, newSum)
            }
But the most confusing thing in all these is the
fold
syntax and that's not my fault.
Was I joking? Honestly don't know! It clearly was a goal to reduce the need for local vars. But try and refactor it to make it more readable, bet you can't make much improvement, because as I say, the body of it is
fold
and that's plain hard to read. I tried to give good names to its arguments, but there's not a lot more you can do.
So maybe this is better than the
.let{ newSum ->
but it's subjective:
Copy code
fun List<Int>.maxSubListSum(n: Int) =
    foldIndexed(0 to 0) { i, (sum, max), next ->
        val newSum = sum + next - (getOrNull(i - n) ?: 0)
        newSum to max(max, newSum)
    }.second
Less nesting, bit cleaner. Comment could help, but I'm allergic to them.
l
"Explicit return type would make the code more readable."
Maybe, and or just turn on hints in your IDE. I'm on Slack, not in an IDE, and indentation is not the best in your snippet IMHO, hence my comment.
I think your last snippet is more readable, but it's still hard to figure out the return type by reading
FYI, Kotlin strives for readability, not for concision:

https://youtu.be/PsaFVLr8t4E?t=187

i
@Alan Evans thanks for solution. As I mentioned optimisation is not important here as I am working on my repo containing Kotlin programming puzzles and I want to show not optimal solutions as well (https://github.com/igorwojda/kotlin-coding-puzzle). Anyway you aproach was interesting, so thx for inspiration.
a
@louiscad Many languages don't even have return types at all, yet people manage to use them just fine. I think the key to readability is the naming, and
maxSubListSum
tells you that the result is a
Sum
of part of the list of
Int
. Suppose I had
maxSubListSum(n: Int): Int
and
maxSubListProduct(n: Int): Int
. Both return
Int
, but only the function name tells you what the function returns, the rest is just noise, only relevant if you were actually using the function, in which case you'd be in an IDE, not slack.
d
There are two aspects to what a function returns - the type and something about how it is computed. Just because it's a sum doesn't mean it will be an Int. A sum over a
List<Int>
should actually be represented as a
Long
to be stable, so I get that there is a clue, it doesn't mean that we don't need the IDE to tell us the actual type. In my opinion, when an expression covers 4-5 lines, it's generally too long and the programmer probably could've spent less time writing it as statements.
1
l
@Alan Evans It could return a
Number
or something else despite the name, and a PR reviewer would not know if not reviewing in an IDE, like most of the time.
d
I don't mean to criticize your style, but if I were working with you, I'd give points for adding the return type. I value that kotlin is a statically typed language, I think it improves my productivity significantly, when comparing to when I used python or JavaScript, which are dynamically typed and thus can't provide the same compile time analysis that kotlin can. It helps to know the return type at a glance for the programmer to work in this powerful environment.
a
"A sum over a
List<Int>
should actually be represented as a
Long
to be stable", that would be unexpected as the standard functions don't do that
public fun Iterable<Int>.sum(): Int
"when an expression covers 4-5 lines, it's generally too long and the programmer probably could've spent less time writing it as statements.", not much less as I did write as statements, and then I inlined it! If I were working with you, I'd be applying the style the team decides.
d
On the other hand, similar methods in the JDK do return
long
. I agree that the style decided on by the team takes priority :)
I don't mean to start an argument. You came up with a nice algorithm, better than what I proposed. Well done.
And I should not have gone the way of "If I were working with you" in hindsight.
a
No it's fine. And sorry to come across as so defensive, my only point with that was I don't really care, makes no difference to me if the type is there or not, so I would absolutely do what the team prefers.
👍🏻 1