Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

330
Views
Split a lists into multiple sub lists with predicate - looking for a nice way to write this code

Lets say I have a list of integers: [2, 4, 4, 6, 1, 8, 3, 5, 2, 2, 2], and I want to split this lists into sub lists so each sub list contain values that match the predicate, or if it doesn't then only the value that didn't match, and it should be in the order of the original list.

So for example, if the predicate is "is even" I expect to get the following result: [[2, 4, 4, 6],[1],[8],[3, 5],[2, 2, 2]]

I have a code that works, but it's pretty ugly in my opinion and I feel like there should be a much nicer way to write it:

private fun <T : Any> toSubLists(values: List<T>, predicate: (T) -> Boolean): List<List<T>> {
  val subLists = mutableListOf<List<T>>()
  var currentList = mutableListOf<T>()
  values.forEach {
    if (!predicate(it)) {
      if (currentList.isNotEmpty()) {
        subLists.add(currentList)
        currentList = mutableListOf()
      }
      subLists.add(listOf(it))
    } else {
      currentList.add(it)
    }
  }
  if (currentList.isNotEmpty()) {
    subLists.add(currentList)
  }
  return subLists
}
over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

Not sure if it's better because it might be harder to understand, but this is a way to do it

private fun <T : Any> toSubLists(values: List<T>, predicate: (T) -> Boolean): List<List<T>> = 
    values.withIndex().groupBy({
        var index = it.index
        while (index != 0 && predicate(values[index]) && predicate(values[index - 1])) index--
        index
    }){
        it.value
    }.values.toList()

see it working here

over 4 years ago · Santiago Trujillo Report

0

There is a feature request for a generic version of this that accepts other key selectors than predicates.

In the meantime, for your use case I think we can simplify a bit:

fun <T> List<T>.groupRunsBy(predicate: (T) -> Boolean): List<List<T>> {
    val result = mutableListOf<MutableList<T>>()
    var currentlyMatching: Boolean? = null
    forEach {
        val itemMatches = predicate(it)
        if (itemMatches == currentlyMatching) {
            result.last().add(it)
        } else {
            currentlyMatching = itemMatches
            result.add(mutableListOf(it))
        }
    }
    return result
}

fun main() {
    val list = listOf(2, 4, 4, 6, 1, 8, 3, 5, 2, 2, 2)
    
    println(list.groupRunsBy { it % 2 == 0 }) // [[2, 4, 4, 6], [1], [8], [3, 5], [2, 2, 2]]
}

Tested here: https://pl.kotl.in/OHVr7S6lX

This version can easily be changed to support any selector that returns non-null keys.

over 4 years ago · Santiago Trujillo Report

0

fun <T : Any> toSubLists(values: List<T>, predicate: (T) -> Boolean): List<List<T>> {
  val items = values.map { predicate(it) to listOf(it) }.toMutableList()
  for (i in items.indices.last downTo 1) {
    if (items[i - 1].first && items[i].first) {
      items[i - 1] = items[i - 1].first to items[i - 1].second + items[i].second
      items.removeAt(i)
    }
  }
  return items.map { it.second }
}

val list1 = listOf(2, 4, 4, 6, 1, 8, 3, 5, 2, 2, 2)
val isOdd: (Int) -> Boolean = { it % 2 != 0 }
val isEven: (Int) -> Boolean = { it % 2 == 0 }

println(toSubLists(list1, isOdd))   // [[2], [4], [4], [6], [1], [8], [3, 5], [2], [2], [2]]
println(toSubLists(list1, isEven))  // [[2, 4, 4, 6], [1], [8], [3], [5], [2, 2, 2]]
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!