Last active
July 24, 2020 07:22
-
-
Save ConorGarry/1108327330213cb428bc6d176b1036f1 to your computer and use it in GitHub Desktop.
Kotlin extension function for paritioning >2 predicates.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Similar to [groupBy] or [partition], except an arbitrary amount of predicates can be returned. | |
* Think [partition] for > 2 predicates. | |
* | |
* | |
* @return [List] with size n for predicates where all items will satisfy one of the predicates, | |
* or size n + 1 for n predicates, where there will be remaining items after condition check. | |
* | |
* @throws [IndexOutOfBoundsException] If using declaration deconstruction where val count is > possible return size. | |
* | |
* e.g. will fail a range check because to many vals are expected. | |
* ``` | |
* val (a, b, c) = groupByPredicates({ it < 2 }, { it < 4 }) | |
* ``` | |
* But this won't throw, a and b be will be populated, the remainder is ignored. | |
* ``` | |
* val (a, b) = groupByPredicates({ it < 2 }, { it < 4 }, { it < 6 }) | |
* ``` | |
*/ | |
fun <T> Iterable<T>.groupByPredicates(vararg predicates: (T) -> Boolean): List<List<T>> { | |
val result = mutableListOf<List<T>>() | |
val remainder = predicates.fold(this, { list, predicate -> | |
list.partition(predicate).run { | |
result += first | |
second | |
} | |
}).toList() | |
if (remainder.isNotEmpty()) result += remainder.toList() | |
return result | |
} | |
// Test | |
class GroupByPredicatesTest { | |
@Test | |
fun testGroup() { | |
// List 1–20 | |
val list20 = List(20) { it.inc() } | |
val grouped = list20.groupByPredicates({ it < 5 }, { it < 10 }, { it < 15 }) | |
assertTrue("List size should be 4 (n + 1 predicates)", grouped.size == 4) | |
assertTrue("List 0 should be 1–4", grouped[0] == listOf(1, 2, 3, 4)) | |
assertTrue("List 1 should be 5–9", grouped[1] == listOf(5, 6, 7, 8, 9)) | |
assertTrue("List 2 should be 10–14", grouped[2] == listOf(10, 11, 12, 13, 14)) | |
assertTrue("List 3 should be 15–20", grouped[3] == listOf(15, 16, 17, 18, 19, 20)) | |
// No remainder check. | |
val groupedNoRemainder = list20.groupByPredicates({ it <= 10 }, { it > 10 }) | |
assertTrue("List size should be 2 (n predicates)", groupedNoRemainder.size == 2) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment