Skip to content

Commit 26ce9e0

Browse files
committed
Factor out a filterMaxBy() function on Iterable
It filters the collection by the maximum element according to the given selector function. This enables writing maximum filters without breaking the code's flow. See ReindeerOlympics.kt as an example.
1 parent e8e7622 commit 26ce9e0

File tree

3 files changed

+26
-6
lines changed

3 files changed

+26
-6
lines changed

src/main/kotlin/de/ronny_h/aoc/extensions/collections/Lists.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,12 @@ fun List<String>.split(delimiter: String = ""): List<List<String>> {
2626
}
2727
return result
2828
}
29+
30+
/**
31+
* @return The [Iterable] of elements that maximize the given [selector].
32+
*/
33+
inline fun <T, R : Comparable<R>> Iterable<T>.filterMaxBy(selector: (T) -> R): Iterable<T> {
34+
if (none()) return this
35+
val max = maxOf(selector)
36+
return filter { selector(it) == max }
37+
}

src/main/kotlin/de/ronny_h/aoc/year2015/day14/ReindeerOlympics.kt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package de.ronny_h.aoc.year2015.day14
22

33
import de.ronny_h.aoc.AdventOfCode
4+
import de.ronny_h.aoc.extensions.collections.filterMaxBy
45
import kotlin.math.min
56

67
fun main() = ReindeerOlympics().run(2660, 1256)
@@ -15,12 +16,10 @@ fun List<Reindeer>.maxReindeerDistanceIn(secondsTotal: Int) = map { it.reindeerD
1516
fun List<Reindeer>.pointsOfWinnerIn(secondsTotal: Int): Int {
1617
val reindeerPoints = MutableList(size) { 0 }
1718
for (seconds in 1..secondsTotal) {
18-
val distances = map { it.reindeerDistanceIn(seconds) }.withIndex()
19-
val leaderDistance = distances.maxOf { it.value }
20-
val leaders = distances.filter { it.value == leaderDistance }
21-
leaders.forEach {
22-
reindeerPoints[it.index]++
23-
}
19+
map { it.reindeerDistanceIn(seconds) }
20+
.withIndex()
21+
.filterMaxBy(IndexedValue<Int>::value)
22+
.forEach { reindeerPoints[it.index]++ }
2423
}
2524
return reindeerPoints.max()
2625
}

src/test/kotlin/de/ronny_h/aoc/extensions/collections/ListsTest.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,16 @@ class ListsTest : StringSpec({
3131
"split a list with multiple blocks ending with the delimiter line" {
3232
listOf("a", "b", "", "c", "d", "").split("") shouldBe listOf(listOf("a", "b"), listOf("c", "d"))
3333
}
34+
35+
"filterMaxBy an empty list returns an empty list" {
36+
emptyList<String>().filterMaxBy(String::length) shouldBe emptyList()
37+
}
38+
39+
"filterMaxBy with a unique max returns exactly that" {
40+
listOf("1", "123", "12").filterMaxBy(String::length) shouldBe listOf("123")
41+
}
42+
43+
"filterMaxBy with more than one max element returns all max elements" {
44+
listOf("1", "123", "321").filterMaxBy(String::length) shouldBe listOf("123", "321")
45+
}
3446
})

0 commit comments

Comments
 (0)