Skip to content

Instantly share code, notes, and snippets.

@JonNorman
Created June 5, 2020 17:30
Show Gist options
  • Save JonNorman/794ab875c810d30fca3b5604f7fd0726 to your computer and use it in GitHub Desktop.
Save JonNorman/794ab875c810d30fca3b5604f7fd0726 to your computer and use it in GitHub Desktop.
Grouping Sublists
import org.scalatest.FlatSpec
object GroupTask {
/**
* A function that can group a list of any type into sub-lists according to some condition.
*
* Because of the way we can pattern match on `List`s and extract their values via the "cons" operator - :: - we
* can build up our List of Lists as we go, adding a new list to the front whenever we find that the current element
* cannot be added to the current list.
*
* Once we have finished iterating over all of our input elements, we will end up with our lists in the wrong order
* (since we are prepending each successive list rather than appending it) - this is easily solved! We can just
* reverse the list when we're done 😀
*
* @param canBeAddedToList - a function by which we can determine whether an element of that type can be added to a given list of that type or not.
* @param as - the initial list of our elements
* @tparam A - the type of the elements
*/
def group[A](canBeAddedToList: (A, List[A]) => Boolean)(as: List[A]): List[List[A]] =
as.foldLeft(List(List.empty[A])) { (acc, a) =>
acc match {
case currentList :: tail if canBeAddedToList(a, currentList) =>
::(currentList :+ a, tail)
case _ =>
::(::(a, Nil), acc)
}
}
.reverse
def alexisCondition(candidate: Int, group: List[Int], maximumInclusiveThreshold: Int = 10): Boolean =
group.sum + candidate <= maximumInclusiveThreshold
// we can combine our generic function and the "condition" function here to give us the function we want
def groupAlexis(numbers: List[Int]) =
group[Int](alexisCondition(_, _))(numbers)
}
class GroupTaskSpec extends FlatSpec {
"the example" should "work" in {
val input = List(1, 5, 3, 7, 6, 7, 3, 9, 3, 5)
val expected = List(List(1, 5, 3), List(7), List(6), List(7, 3), List(9), List(3, 5))
val actual = GroupTask.groupAlexis(input)
assert(actual == expected)
}
"an empty list" should "return a list containing an empty list" in {
val input = List.empty[Int]
val expected = List(List.empty[Int])
val actual = GroupTask.groupAlexis(input)
assert(actual == expected)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment