Advent of Code 2021 day 3
12/03/2022, 5:00 AMMarcin Wisniowski
12/03/2022, 5:13 AMMichael de Kaste
12/03/2022, 5:17 AMobject Day3 : Challenge() {
val parsed = input.lines()
private fun valueExtract(char: Char) = if(char.isLowerCase()) char - 'a' + 1 else char - 'A' + 27
override fun part1() = parsed
.map { it.chunked(it.length / 2) }
.map { (a,b) -> a.first(b::contains) }
.sumOf(::valueExtract)
override fun part2() = parsed.chunked(3)
.map { (a,b,c) -> a.first { it in b && it in c } }
.sumOf(::valueExtract)
}
Michael de Kaste
12/03/2022, 5:18 AM(a,b) -> a.first{ b.contains(a) }
and I just couldn't find what I did wrong, xdKroppeb
12/03/2022, 5:21 AMCognitive Gear
12/03/2022, 5:22 AMKroppeb
12/03/2022, 5:23 AMtoSet()
also existsMarcin Wisniowski
12/03/2022, 5:25 AMMichael de Kaste
12/03/2022, 5:26 AMCognitive Gear
12/03/2022, 5:29 AMwakingrufus
12/03/2022, 5:29 AMJakub Gwóźdź
12/03/2022, 5:30 AMa.intersect(b)
function, even if I knew it existed (and wasted half a minute scrolling the Set
member methods), so i just went with a.filter { it in b }
🙂wakingrufus
12/03/2022, 5:30 AMVlad Petrushkevich
12/03/2022, 5:31 AMval ALPHABET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
fun part1(input: List<String>): Int {
return input
.map { s1 ->
val mid: Int = s1.length / 2
s1.substring(0, mid) to s1.substring(mid)
}
.sumOf { (s1, s2) ->
val union = s1.toSet().intersect(s2.toSet())
union.sumOf { ALPHABET.indexOf(it).inc() }
}
}
fun part2(input: List<String>): Int {
val windowSize = 3
return input
.windowed(windowSize, windowSize)
.sumOf { rucksacks ->
val unique = rucksacks
.map { it.toSet() }
.reduce { init, item -> init.intersect(item) }
unique.sumOf { ALPHABET.indexOf(it).inc() }
}
}
When you forget how to calculate index of letter with charcode, .indefOf() hardcoded alphabet comes to the resque)Kroppeb
12/03/2022, 5:33 AMMarcin Wisniowski
12/03/2022, 5:34 AMJakub Gwóźdź
12/03/2022, 5:34 AMMichael de Kaste
12/03/2022, 5:37 AMDavid Whittaker
12/03/2022, 5:37 AMmap
reduce
and filter
. Old fashioned way:Jan Durovec
12/03/2022, 5:38 AMMarcin Wisniowski
12/03/2022, 5:38 AM('a'..'z') + ('A'..'Z')
to generate itCognitive Gear
12/03/2022, 5:38 AMJakub Gwóźdź
12/03/2022, 5:43 AMDavid Whittaker
12/03/2022, 5:44 AMKroppeb
12/03/2022, 5:45 AMwindowed(x, x)
you can also use chunked(x)
Kroppeb
12/03/2022, 5:46 AMCognitive Gear
12/03/2022, 5:47 AMKroppeb
12/03/2022, 5:50 AMKroppeb
12/03/2022, 5:52 AMMichael Böiers
12/03/2022, 5:55 AMDan Fingal-Surma
12/03/2022, 6:07 AMephemient
12/03/2022, 6:08 AMephemient
12/03/2022, 6:08 AMLong
to represent a set of small integers, since it should be faster than Set<Int>
ephemient
12/03/2022, 6:08 AMCognitive Gear
12/03/2022, 6:08 AMDirk Groot
12/03/2022, 6:09 AMDirk Groot
12/03/2022, 6:10 AMPoisonedYouth
12/03/2022, 6:53 AMjonas.app
12/03/2022, 6:59 AMPaul Woitaschek
12/03/2022, 7:11 AMjonas.app
12/03/2022, 7:14 AMNeil Banman
12/03/2022, 7:20 AMVenkataramanan Parameswaran
12/03/2022, 7:24 AMritesh
12/03/2022, 7:31 AMchuncked
, sumOf
and intersect
Kroppeb
12/03/2022, 7:32 AMritesh
12/03/2022, 7:33 AMval (first, second) = item.chunked(item.length / 2)
Jakub Gwóźdź
12/03/2022, 7:35 AMritesh
12/03/2022, 7:40 AMVenkataramanan Parameswaran
12/03/2022, 7:44 AMephemient
12/03/2022, 7:45 AMritesh
12/03/2022, 7:46 AMtoCharArray
can be removed.ephemient
12/03/2022, 7:48 AMLong
acting as a bitset, for an massive speedupPaul Woitaschek
12/03/2022, 7:48 AMjonas.app
12/03/2022, 7:49 AMPaul Woitaschek
12/03/2022, 7:51 AMWael Ellithy
12/03/2022, 8:22 AMritesh
12/03/2022, 8:26 AMGrzegorz Baczek
12/03/2022, 8:32 AMrenatomrcosta
12/03/2022, 8:39 AMKroppeb
12/03/2022, 8:40 AMrenatomrcosta
12/03/2022, 8:47 AMthis.splitOnLineBreaks()
.map {
val size = it.length - 1
it.toCharArray(0, (size / 2) + 1) to it.toCharArray((size / 2) + 1, size + 1)
}
.map { (c1, c2) -> c1.toList() to c2.toList() }
So before putting it in public, I wanted to quickly clean it up haha. Ended up not looking back at pt2 tho
(ah, also, the chunked in pt1 is to separate the compartments only. pt2 didn't really call for that, just the windowed worked out ok for the full strings)PoisonedYouth
12/03/2022, 8:59 AMWilerson Oliveira
12/03/2022, 9:10 AMKroppeb
12/03/2022, 9:11 AMwindowed(n,n)
is the same as chunked(n)
Kroppeb
12/03/2022, 9:11 AMKroppeb
12/03/2022, 9:13 AMephemient
12/03/2022, 9:14 AMitemTypes.zip(priorities).toMap()
does the samephldavies
12/03/2022, 9:14 AMephemient
12/03/2022, 9:15 AMpriorities
if you wanted,
itemTypes.withIndex().associateBy(keySelector = { it.value }, valueTransform = { it.index + 1 })
Joakim Tall
12/03/2022, 9:23 AMJoakim Tall
12/03/2022, 9:23 AMJoakim Tall
12/03/2022, 9:26 AMephemient
12/03/2022, 9:29 AM.map { (a, b, c) ->
Joakim Tall
12/03/2022, 9:31 AMCharles Flynn
12/03/2022, 10:18 AMinput
.map { it.splitIntoHalfSets() }
.map { it.first.intersect(it.second).first() }
.sumOf { it.toPriority() }
vs
input.sumOf {
val (firstHalf, secondHalf) = it.splitIntoHalfSets()
val commonItem = firstHalf.intersect(secondHalf).first()
commonItem.toPriority()
}
Is there any performance difference? Is one more readable than the other?phldavies
12/03/2022, 10:25 AMinput
is a List, each map
returns a new list with the transformed elements. As such the sumOf
alone would have better performance. I'd normally use separate mapping steps if they make sense to reason over them separately, and use asSequence
to make it lazy and mitigate some of the performance impact.Charles Flynn
12/03/2022, 10:53 AMsumOf
approach but made various functions in a style making it easy to read. Think my solution reads well in the end:
https://github.com/CfGit12/aoc-2022/blob/master/src/main/kotlin/aoc2022/3.ktxxfast
12/03/2022, 10:59 AM.toSet
and `intersect`s
fun Sequence<Set<Char>>.scored() = this
.map { it.map { char -> if (char.isLowerCase()) char - 'a' + 1 else char - 'A' + 27 } }
.flatten()
.sum()
fun part1(input: List<String>) = input.asSequence()
.map { rucksack -> rucksack.chunked(rucksack.length / 2) }
.map { (first, second) -> first.toSet() intersect second.toSet() }
.scored()
fun part2(input: List<String>) = input.asSequence()
.chunked(3)
.map { (first, second, third) -> first.toSet() intersect second.toSet() intersect third.toSet()}
.scored()
Jakub Gwóźdź
12/03/2022, 11:13 AMJakub Gwóźdź
12/03/2022, 11:14 AMFredrik Rødland
12/03/2022, 11:14 AMphldavies
12/03/2022, 11:19 AMJakub Gwóźdź
12/03/2022, 11:21 AMit in b
and similar comparisonsJakub Gwóźdź
12/03/2022, 11:21 AMphldavies
12/03/2022, 11:22 AMOleksandr Balan
12/03/2022, 11:27 AMJakub Gwóźdź
12/03/2022, 11:29 AMKevin Del Castillo
12/03/2022, 4:07 PMintersect
made things more clear (code):Kroppeb
12/03/2022, 4:12 PMKevin Del Castillo
12/03/2022, 4:14 PMIterable
to a set, so in the case you were already using a set I'd like to believe that this step is just an identity, right?Karloti
12/03/2022, 4:14 PMKroppeb
12/03/2022, 4:15 PMKevin Del Castillo
12/03/2022, 4:18 PMFredrik Rødland
12/03/2022, 4:18 PMI'd like to believe that this step is just an identity
-> I don't think so...
Set.intersect =
```public infix fun <T> Iterable<T>.intersect(other: Iterable<T>): Set<T> {
val set = this.toMutableSet()
set.retainAll(other)
return set
}```Set.toMutableSet =
```public fun <T> Iterable<T>.toMutableSet(): MutableSet<T> {
return when (this) {
is Collection<T> -> LinkedHashSet(this)
else -> toCollection(LinkedHashSet<T>())
}
}```
Fredrik Rødland
12/03/2022, 4:19 PMKevin Del Castillo
12/03/2022, 4:20 PMIterable
set to a set is not an identity, then it's better to just call intersect
directly onto the strings, right? 🤔phldavies
12/03/2022, 4:22 PMIterable
is converted to `Set`(even when operating on a set) is because you want a new Set
to be returned. The optimization would be to iterate through other
and only add to the new set based on it in this
(assuming this
has optimal contains
performance)Kroppeb
12/03/2022, 4:22 PMKroppeb
12/03/2022, 4:24 PMKevin Del Castillo
12/03/2022, 4:24 PMSet
makes a lot of senseKevin Del Castillo
12/03/2022, 4:28 PMintersect
if other
is a Set
(as @phldavies mentioned, I guess in this case it depends on the contains
performance)aaronkorver
12/03/2022, 5:18 PMval priorities = ('a'..'z').associateWith { it.code - 96 } + ('A'..'Z').associateWith { it.code - 38 }
I've seen some other ways to do the priority calc, but I haven't seen this yet. Sharing my char ranges map. It isn't the most clever, but it is another way.ephemient
12/03/2022, 5:27 PMfun Char.priority(): Int = (code - 38) % 58
Emerson Farrugia
12/03/2022, 5:35 PMSam Painter
12/03/2022, 6:01 PMBen Hope
12/03/2022, 7:20 PMphldavies
12/03/2022, 7:25 PMKristian Nedrevold
12/03/2022, 7:40 PMDavio
12/04/2022, 10:19 AMobject Day3 {
fun getResultPart1() = getInputAsSequence()
.map { line -> line.chunked(line.length / 2) }
.map { compartments ->
compartments[0].first { c -> compartments[1].contains(c) }
}.sumOf { c -> getPriority(c) }
fun getResultPart2() = getInputAsSequence()
.chunked(3)
.map { rucksacks ->
rucksacks[0].first { c -> rucksacks[1].contains(c) && rucksacks[2].contains(c) }
}.sumOf { c -> getPriority(c) }
private fun getPriority(c: Char): Int = (c.lowercaseChar().code - '`'.code) + if (c.isUpperCase()) 26 else 0
}
Davio
12/04/2022, 10:20 AM'a'
in the ASCII / UTF tableDavio
12/04/2022, 10:20 AMtoUppercase
part is just to calculate the extra offset for uppercase letters which have higher priority