[Thread] Links to my solution and post.
# advent-of-code
t
[Thread] Links to my solution and post.
🎉 2
a
I like your idea of mapNotNull. But it is flawed. Your solution makes multiple comparisons twice and it fails for the case of having the number 1100 in the input since you are pairing every number with itself. Also in part 2 you could get more efficient if you would break if a and b are already greater than 2020.
e
also, it's a pretty close call, but according to my benchmarks,
.asSequence()
is slower than just using
List<Int>
29.640 ± 0.241 ms with sequence, 28.418 ± 0.500 ms without
t
I don’t view making more comparisons than needed a fatal flaw. The argument about 1010 makes sense. A coworker and I were taking about this and I have a new idea but it’s slightly more complicated and solves both issues.
Good to know about sequence vs List. I just went with sequence so I could attempt to describe lazy evaluation. Probably not a great example.
Copy code
private val input = data.sorted()

    fun solvePart1(): Int =
        input.asSequence().mapIndexedNotNull { idx, a ->
            input.asSequence().drop(idx).firstOrNull { a + it == 2020 }?.let { a * it }
        }.first()

    fun solvePart2(): Int =
        input.asSequence().mapIndexedNotNull { aIdx, a ->
            input.asSequence().drop(aIdx).mapIndexedNotNull { bIdx, b ->
                input.asSequence().drop(bIdx).firstOrNull { a + b + it == 2020 }?.let { a * b * it }
            }.firstOrNull()
        }.first()
Sequence version finished a lot faster for me, but I was just using what IntelliJ tells me it took JUnit to finish.
e
I benchmarked with JMH, which warms up the JVM's JIT etc. first. might be the difference.
t
Yeah, I figured you had. I should really learn how to use that, I see people use it but I've only done basics with it and don't think to use it. 🙂
e
in general I would also expect
.drop().asSequence()
to perform better than
.asSequence().drop()
, since the former should be calling
.subList()
underneath and the latter actually iterates… but there's only 200 so it probably doesn't make a big difference here either
you might want
.drop(idx + 1)
, otherwise you could be including the same element twice, but we don't actually have duplicates in our solutions so 🤷 it also doesn't really matter
t
D'oh!
I also just changed it again:
.drop(idx+1).dropWhile { a + it < 2020 }.take(1).firstOrNull { a + it == 2020 }...
And you're right about the sequences. I got attached to them because at some point I want to explain the lazy eval thing, but there will probably be a better one for that later.
e
fencepost errors are the bane of anything index-related :(
t
There are only two hard problems in computer science: 1) Cache invalidation. 2) Naming things. 3) Off-by-one errors.
a
@todd.ginsberg about performance: It might not matter on day 1, but these puzzles get harder every day and performance will matter in future puzzles
t
@Astronaut4449 Yup, totally aware of that! This is my 5th year doing AoC. I'm fine with optimizing when something calls for it, but for code that I write once, run with an automated test, and doesn't have any real business purpose other than me explaining it on a blog post, I don't spend too much time optimizing if it makes it less clear. 🙂