Skip to content

Instantly share code, notes, and snippets.

@JavadocMD
Last active August 29, 2015 14:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JavadocMD/9b0e5fcfa35952886f30 to your computer and use it in GitHub Desktop.
Save JavadocMD/9b0e5fcfa35952886f30 to your computer and use it in GitHub Desktop.
Picking items from a list one-by-one
// Combining a list of options...
val options = List("a", "b", "c", "d")
// ... with a sequence of "picks" to make...
val choices = List(0, 2, 1, 0)
// ... should yield a re-ordered list as so.
val expects = List("a", "d", "c", "b")
// Assume we don't have to worry about out-of-bounds choices.
// worked example:
// pick 0 from {a,b,c,d} -> a
// pick 2 from { b,c,d} -> d
// pick 1 from { b,c } -> c
// pick 0 from { b } -> b
// Solution using a one-off mutable structure.
val ans1 = {
val buff = options.to[ListBuffer]
choices.map(buff.remove(_))
}
// Solution using purely immutable structures.
val ans2 = {
@tailrec def sub(result: List[String], options: List[String], choices: List[Int]): List[String] =
choices match {
case Nil => result
case c :: cs => sub(options(c) :: result, options.take(c) ++ options.drop(c+1), cs)
}
sub(Nil, options, choices).reverse
}
// true
ans1.equals(expects)
ans2.equals(expects)
@tpolecat
Copy link

In real life I would accumulate an Option[List[A]] but this is equivalent to what you have above.

def choose[A](as: List[A], ns: List[Int]): List[A] =
  ns.foldLeft((as, List.empty[A])) { case ((as, acc), n) =>
    (as.patch(n, Nil, 1), as(n) :: acc)
  }._2.reverse

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment