Skip to content

Instantly share code, notes, and snippets.

@ConorGarry
Last active July 24, 2020 07:22
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ConorGarry/1108327330213cb428bc6d176b1036f1 to your computer and use it in GitHub Desktop.
Save ConorGarry/1108327330213cb428bc6d176b1036f1 to your computer and use it in GitHub Desktop.
Kotlin extension function for paritioning >2 predicates.
/**
* 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