:warning: Day 6 Solution Thread  :warning:
# advent-of-code
a
⚠️ Day 6 Solution Thread  ⚠️
Copy code
private val input = readInput("input6.txt")

fun main() {
    input.split("\n\n").map { group ->
        group.split("\n").map { it.toCharArray().toList() }.flatten().groupBy { it }.size
    }.sum().let { println("Part 1: $it") }

    input.split("\n\n").map { group ->
        group.split("\n").map { it.toCharArray().toList() }.flatten().groupBy { it }
            .map { it.value }.filter { it.size == group.split("\n").size }.size
    }.sum().let { println("Part 2: $it") }
}
groupBy RULES
b
that's a fun way
🙂 1
a
I messed up because I kept trying to flatten with the char array and I kept getting errors
that dropped me at least a minute
how’d you do it @bjonnh
b
I have to bring it to that machine
A sec
Copy code
fun main() {
    val groups = textFile("data/2020/06_input.txt").split("\n\n")

    groups.map {
        it.replace("\n", "").toSet().size
    }.sum().let { println(it) }


    groups.map {
        val x = it.split("\n").map {
            it.toSet()
        }
        x.fold(x.first()) { acc, value ->
            acc.intersect(value)
        }.size
    }.sum().let { println(it) }
}
I don't like my fold solution
a
i guessed you had fold 😂
i like it though!
k
reduce
I'm an idiot
I couldn't come up with the name
b
why did you guessed I had fold?
yes that's reduced that I looked for as well
I don't know why fold always come first in my head
a
I think I saw you use fold before a few times
k
huh
b
hah 😄
I did that yesterday for the binary partition
I had a working binary partition 10-liner
before realizing that it was just binary…
k
Oh, i typed
+u
instead of
+b
b
I'm looking at a python solution, it is gross 😄
d
I took the long way and made a mutableMap - sigh
👾 2
a
yep @bjonnh I did that too
b
3 liner:
Copy code
val groups = textFile("data/2020/06_input.txt").split("\n\n")
    println(groups.sumBy { it.replace("\n", "").toSet().size })
    println(groups.sumBy { it.split("\n").map { it.toSet() }.reduce { a, v -> a.intersect(v) }.size })
🎉 2
The Kotlin standard library is great, there are a lot of useful stuff in there
👆 1
I'm looking at one of the top of the leaderboard github account
they are professionals competitive coders
the person has a "book" (really a repo) with tons of functions they use in competitions
they also don't share their solutions…
a
Do you think they remember them all
b
one of them is using vim macros
(and of course regexps)
a
can you link that one
b
yep that's even better than just vim: https://github.com/tckmn/polyaoc-2020
doing it in haskell is pure self flagellation 😄
😂 2
one also has is own language for code golfing
a
Ty
Wow who
b
solution for day 5 part 1 is 11 bytes
😮 2
they even have a special code-page so it takes less space than UTF8
🤣 2
a
...
respect 😂
b
oh they don't compete with the language
they do it after
e
https://github.com/ephemient/aoc2020/blob/main/kt/src/main/kotlin/io/github/ephemient/aoc2020/Day6.kt bitsets, easy peasy. don't need real sets or to break down into groups ahead of time
well maybe not easy, but fast
e
Day 6 was pretty easy, I wrote the solution before I started thinking. Like, I just wrote the first things that came to my mind. Probably would've been slow if I had started thinking about them. Anyway, slightly "golfed" my answer afterwards. Hah, didn't think that chunking by blank lines would come in handy again! Link
j
Copy code
val p06 = suspend {
    val answerLinesPerGroup = input.split("\n\n").map { it.lines() }

    answerLinesPerGroup.map { answerLines ->
        answerLines.joinToString("").groupingBy { it }.eachCount().keys.count()
    }.sum().print { "Part 1: $it" }

    answerLinesPerGroup.map { answerLines ->
        answerLines.joinToString("").groupingBy { it }.eachCount().filterValues { it == answerLines.size }.keys.count()
    }.sum().print { "Part 2: $it" }

}
I spent some time trying to get rid of the duplication but couldn't find an elegant way to retain the group size so just did it like this
a
I initially just used a Set to extract unique characters for Part 1 but reworked my solution when I saw part 2:
Copy code
fun main() {
    val groupDeclarations: List<List<String>> = resourceFile("day06/DeclarationForm.txt").readText()
        .split("\n\n")
        .map { it.split("\n") }
    println(groupDeclarations.sumBy { declarations -> ('a'..'z').filter { c -> declarations.any { it.contains(c) } }.size })
    println(groupDeclarations.sumBy { declarations -> ('a'..'z').filter { c -> declarations.all { it.contains(c) } }.size })
}
m
can anyone tell me why this works:
Copy code
private val parsed = input.split("\r\n\r\n").map { it.lines().map(String::toSet) }

override fun part1() = parsed.sumBy{ it.reduce { acc, set -> acc.union(set) }.size }
override fun part2() = parsed.sumBy{ it.reduce { acc, set -> acc.intersect(set) }.size }
but this only solves correctly for part1? The logic is the same (tried to speed things up)
Copy code
private val parsed = input.split("\r\n\r\n")
        .map {
            it.lines().map {
                it.fold(BitSet(26)){ acc: BitSet, c: Char ->
                    acc.apply { set(c - 'a') }
                }
            }
        }

override fun part1() = parsed.sumBy { it.reduce { acc, bitSet -> acc.apply { or(bitSet) } }.cardinality() } //CORRECT
override fun part2() = parsed.sumBy { it.reduce { acc, bitSet -> acc.apply { and(bitSet) } }.cardinality() } //INCORRECT ?!?
I'm mapping every string to a bitset where 'a' is bit 0 and 'z' is bit 25 then doing 'or' for union and 'and' for intersection, and then counting the 1 bits. the 'and' for intersection part doesn't work for some reason?
n
Set is perfect for both part 1 and 2 though. Literally just change union to intersect.
Copy code
import Utils.*

fun getData() = (aocDataDir / "day6.txt").readText()
    .split("\n\n")
    .map { it.split("\n").filter { it.isNotEmpty() }.map { it.toSet() }}

fun part1() = getData().sumBy { group ->
    group.reduce { acc, set -> acc union set }.size
}

fun part2() = getData().sumBy { group ->
    group.reduce { acc, set -> acc intersect set }.size
}
The key is to create a List <List<Set>> and not List<Set>. I've started to get into the habit of always parsing the data in a way that throws away no information; even if it makes part1 a little longer, it makes part2 much easier because you never have to revisit your parsing
t
Last one in again (hey, I get up and go on a walk and shower before I even look at this). I've solved it, but not elegantly for part 2.
The last record in my dataset is giving me trouble with the newline at the end. Not sure how y'all got around that looking at some of these.
a
How are you splitting the input? I don't have a problem using the following code regardless of how many '\n' characters are at the end of the file:
Copy code
val groupDeclarations: List<List<Set<Char>>> = resourceFile("day06/DeclarationForm.txt").readText()
    .split("\n\n")
    .map { it.lines().map(String::toSet) }
t
Eh, it's the trailing newline on the last record that gives me issues. I split on double newline like most everybody here. That last empty line messes with my "how big is this group" count, but I just ended up lopping it off. 🙂
Copy code
class Day06(input: String) {

    private val answers: List<String> = input.split("\n\n").map { it.removeSuffix("\n") }

    fun solvePart1(): Int =
        answers.map { it.replace("\n", "") }.sumBy { it.toSet().size }

    fun solvePart2(): Int =
        answers.map { it.lines() }.sumBy { group ->
            group
                .joinToString("")
                .groupingBy { it }
                .eachCount()
                .count { it.value == group.size }
        }
}
I'll probably revise this. It doesn't feel right.
n
I filtered out empty lines after doing the map inside the split
That got me too at first
a
I like the simplicity of just using the reduce() function on List<List<Set<Char>>>> for both parts.
Copy code
println(groupDeclarations.sumBy { it.reduce{ acc,declaration -> acc.union(declaration)}.size })
println(groupDeclarations.sumBy { it.reduce{ acc,declaration -> acc.intersect(declaration)}.size })
t
Yeah, that's a really nice solution there.
@Nir Yeah, I see that now. 🙂
j
The timings per platform for my solution posted 7 hours ago 🙂
Copy code
| Platform         | Average (ms)           | Measurements (ms) |
| -----------------| ----------------------:|------------------:|
| JVM (OpenJDK 11) |  7.4 ± 10.7   | `52, 10, 11, 12, 7, 5, 8, 6, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2` |
| Node JS          | 19.4 ± 21.0   | `108, 29, 20, 22, 13, 11, 11, 11, 14, 13, 15, 16, 13, 12, 11, 15, 9, 12, 10, 14` |
| Native           | 58.5 ±  5.0   | `64, 61, 63, 55, 58, 56, 65, 54, 56, 58, 72, 62, 54, 52, 54, 55, 59, 52, 52, 59` |
d
hi guys, I have stumbled upon the issue with this. The page doesn't accept my answer (3352) for day 6 part 2 as correct. I also run few solutions from this thread, which give me the same answer (3352), but somehow it's not accepted as correct. I have checked if I used wrong input file, but it seems correct, I had no problem with part 1
anyone has any idea?
a
@Dias Is this the problem with the string inputs for questions? I saw some issues mentioned for this day where the browser used to download the input was attempting to automatically translate some of the lines in the input. Not sure if this is cause of your problem
d
interesting, by translating you mean from english to some other language?
tried from different browser, same problem 😞
a
@Dias Yep, so if the translation has recognised an english word & automatically translated it to spanish you will never get the correct solution. Key is to prevent the translation in the browser and then re-download your input file
@Dias - Sorry not sure what the issue is then. Hope someone else can help
d
out of curiosity, what the number you get when you run your solution from the current input?
a
My solution to Day 2 gave an answer of 2947 with my input
d
hmmmmmmmmmmmmmm, doesn't make sense
can you post input here please?
ok, I figured how to make it work, but not sure what's exactly the issue
if I add new line to end of the file it works
a
Ok, mystery solved
d
so it counts the list line feed as part of a "group" which obviously doesn't match characters with rest of the group
I guess I was the only unlucky person which actually affected by this, because all other scripts I tried from this thread are also affected by this issue 😄
1
😄 1
t
I had the same issue with the last newline and had to account for it.