Skip to content

Commit c52650f

Browse files
committed
allUniqueBy() and firstDuplicate() functions on Iterable
Both take a transform function that can be used to pick a specific field used for comparison.
1 parent 9e3aa4d commit c52650f

File tree

2 files changed

+46
-0
lines changed
  • src
    • main/kotlin/de/ronny_h/aoc/extensions/collections
    • test/kotlin/de/ronny_h/aoc/extensions/collections

2 files changed

+46
-0
lines changed

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,26 @@ inline fun <T, R : Comparable<R>> Iterable<T>.minByUniqueOrNull(selector: (T) ->
6464
} while (iterator.hasNext())
6565
return if (minCount == 1) minElem else null
6666
}
67+
68+
/**
69+
* @return `true` if all elements of this [Iterable] are unique after applying the given [transform] function. Else `false`.
70+
*/
71+
inline fun <T, R> Iterable<T>.allUniqueBy(transform: (T) -> R): Boolean {
72+
val hashset = hashSetOf<R>()
73+
return all { hashset.add(transform(it)) }
74+
}
75+
76+
/**
77+
* @return The first transformed element of this [Iterable] that produces a duplicate (i.e. non-unique value) after
78+
* applying the given [transform] function. `null`, if no such element exists.
79+
*/
80+
inline fun <T, R> Iterable<T>.firstDuplicate(transform: (T) -> R): R? {
81+
val hashset = hashSetOf<R>()
82+
for (it in this) {
83+
val transformed = transform(it)
84+
if (!hashset.add(transformed)) {
85+
return transformed
86+
}
87+
}
88+
return null
89+
}

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,27 @@ class ListsTest : StringSpec({
5858
list.minByUniqueOrNull { it } shouldBe expected
5959
}
6060
}
61+
62+
"allUniqueBy" {
63+
forAll(
64+
row(emptyList(), true),
65+
row(listOf(1, 2, 3), true),
66+
row(listOf(1, 1, 3), false),
67+
) { list, unique ->
68+
list.allUniqueBy { it } shouldBe unique
69+
}
70+
}
71+
72+
"firstDuplicate" {
73+
forAll(
74+
row(emptyList(), null),
75+
row(listOf(1), null),
76+
row(listOf(1, 2), null),
77+
row(listOf(1, 2, 2), 2),
78+
row(listOf(1, 2, 2, 3, 3), 2),
79+
row(listOf(1, 3, 3, 2, 2), 3),
80+
) { list, element ->
81+
list.firstDuplicate { it } shouldBe element
82+
}
83+
}
6184
})

0 commit comments

Comments
 (0)