Lazy, breadth-first traversal of a Rose Tree? - scala

I'm trying to refactor a component that currently produces a Seq[X] using a fairly expensive recursive algorithm so that it produces a Stream[X] instead, so X's can be loaded/calculated on-demand, and the producer doesn't have to try to guess beforehand how much digging it'll have to do to satisfy the consumer.
From what I've read, this is an ideal use for an "unfold", so that's the route I've been trying to take.
Here's my unfold function, derived from David Pollak's example, which has been vetted by a certain Mr. Morris:
def unfold[T,R](init: T)(f: T => Option[(R,T)]): Stream[R] = f(init) match {
case None => Stream[R]()
case Some((r,v)) => r #:: unfold(v)(f)
}
And here's a little tree to try our luck with:
case class Node[A](data: A, children: List[Node[A]]) {
override def toString = "Node(" + data + ", children=(" +
children.map(_.data).mkString(",") +
"))"
}
val tree = Node("root", List(
Node("/a", List(
Node("/a/1", Nil),
Node("/a/2", Nil)
)),
Node("/b", List(
Node("/b/1", List(
Node("/b/1/x", Nil),
Node("/b/1/y", Nil)
)),
Node("/b/2", List(
Node("/b/2/x", Nil),
Node("/b/2/y", Nil),
Node("/b/2/z", Nil)
))
))
))
And finally, here's my failed attempt at a breadth-first traversal that uses unfold:
val initial = List(tree)
val traversed = ScalaUtils.unfold(initial) {
case node :: Nil =>
Some((node, node.children))
case node :: nodes =>
Some((node, nodes))
case x =>
None
}
assertEquals(12, traversed.size) // Fails, 8 elements found
/*
traversed foreach println =>
Node(root, children=(/a,/b))
Node(/a, children=(/a/1,/a/2))
Node(/b, children=(/b/1,/b/2))
Node(/b/1, children=(/b/1/x,/b/1/y))
Node(/b/2, children=(/b/2/x,/b/2/y,/b/2/z))
Node(/b/2/x, children=())
Node(/b/2/y, children=())
Node(/b/2/z, children=())
*/
Can anyone give me some hints as to how to fix (or rewrite) my traversal logic so that all the nodes are returned? Thanks!

You just forgot to include the inner nodes' children during the traversal of the tree:
val traversed = unfold(initial) {
case node :: Nil =>
Some((node, node.children))
case node :: nodes =>
// breadth-first
Some((node, nodes ::: node.children))
// or depth-first: Some((node, node.children ::: nodes))
case x =>
None
}

Here is a complete version of Moritz' answer, with a corrected partial function (the last case never matched anything in the original problem):
case class CNode[A](data: A, children: List[CNode[A]]=Nil) {
override def toString: String = if (children.isEmpty) s"node($data)" else
s"node($data, children=(${ children.map(_.data).mkString(",") }))"
}
object Main extends App {
def unfold[T, R](init: T)(f: T => Option[(R, T)]): Stream[R] = f(init) match {
case None => Stream[R]()
case Some((r, v)) => r #:: unfold(v)(f)
}
val tree = List(
CNode("root", List(
CNode("/a", List(
CNode("/a/1", Nil),
CNode("/a/2", Nil)
)),
CNode("/b", List(
CNode("/b/1", List(
CNode("/b/1/x", Nil),
CNode("/b/1/y", Nil)
)),
CNode("/b/2", List(
CNode("/b/2/x", Nil),
CNode("/b/2/y", Nil),
CNode("/b/2/z", Nil)
))
))
))
)
val traversed = unfold(tree) {
case node :: Nil =>
Some((node, node.children))
case node :: nodes =>
// breadth-first
Some((node, nodes ::: node.children))
// or depth-first: Some((node, node.children ::: nodes))
case Nil =>
None
}
println(traversed.force.mkString("\n"))
}

Related

foldLeft vs foldRight vs tailrec on Scala List

Assume I have a collection of c: List[T] sorted.
And I need to make aggregation with foldLeft/foldRight which outputs (List[T],List[T],List[T]), sorted.
To complete this, I have 2 possibilities:
foldLeft, and then reverse each one of the lists (use ::, otherwise its O(n) each step)
foldRight and remain in the same order (use ::)
I know that foldLeft is tailrec implemented and optimized, but making O(n) more steps to reverse the collections, in this use case - which method will generate me better performance?
Assume that the op is O(1)
Example of the code:
def analyzePayload(payload: JsObject, actionRules: List[ActionRule]): InspectorReport = {
val analyzeMode = appConfig.analyzeMode
val (succeed, notApplicable, failed) = actionRules.foldLeft((List[RuleResult](), List[RuleResult](), List[RuleResult]())) { case ( seed # (succeed, notApplicable, failed), actionRule) =>
// Evaluate Single ActionRule
def step(): (List[RuleResult], List[RuleResult], List[RuleResult]) = actionRuleService.eval(actionRule, payload) match {
// If the result is succeed
case EvalResult(true, _, _) => (RuleResult.fromSucceed(actionRule, appConfig.showSucceedAppData) :: succeed, notApplicable, failed)
// If the result is notApplicable
case EvalResult(_, missing #_ :: _, _) => (succeed, RuleResult.fromNotApplicable(actionRule, appConfig.showNotApplicableAppData, missing) :: notApplicable, failed)
// If the result is unmatched
case EvalResult(_, _, unmatched #_ :: _) => (succeed, notApplicable, RuleResult.fromFailed(actionRule, appConfig.showFailedAppData, unmatched) :: failed)
}
analyzeMode match {
case UntilFirstSucceed => if (succeed.isEmpty) step() else seed
case UntilFirstNotApplicable => if (notApplicable.isEmpty) step() else seed
case UntilFirstFailed => if (failed.isEmpty) step() else seed
case Default => step()
case _ => throw new RuntimeException(s"Unknown mode on analyzePayload with mode = ${analyzeMode}")
}
}
InspectorReport(succeed.reverse, notApplicable.reverse, failed.reverse)
}
Before that, I used tailrec which made bad preformance: (why??)
def analyzePayload(payload: JsObject, actionRules: List[ActionRule]): InspectorReport = {
val analyzeMode = appConfig.analyzeMode
def isCompleted(succeed: Int, notApplicable: Int, failed: Int) = {
analyzeMode match {
case Default => false
case UntilFirstSucceed => if (succeed == 0) false else true
case UntilFirstNotApplicable => if (notApplicable == 0) false else true
case UntilFirstFailed => if (failed == 0) false else true
}
}
#tailrec
def analyzePayloadRec(rules: List[ActionRule])(succeed: List[RuleResult], notApplicable: List[RuleResult], failed: List[RuleResult]): (List[RuleResult], List[RuleResult], List[RuleResult]) = {
if (isCompleted(succeed.size, notApplicable.size, failed.size)) (succeed, notApplicable, failed)
else rules match {
// Base cases:
case Nil => (succeed, notApplicable, failed)
// Evaluate case:
case nextRule :: tail =>
actionRuleService.eval(nextRule, payload) match {
// If the result is succeed
case EvalResult(true, _, _) => analyzePayloadRec(tail)(RuleResult.fromSucceed(nextRule, appConfig.showSucceedAppData) :: succeed, notApplicable, failed)
// If the result is notApplicable
case EvalResult(_, missing #_ :: _, _) => analyzePayloadRec(tail)(succeed, RuleResult.fromNotApplicable(nextRule, appConfig.showNotApplicableAppData, missing) :: notApplicable, failed)
// If the result is unmatched
case EvalResult(_, _, unmatched #_ :: _) => analyzePayloadRec(tail)(succeed, notApplicable, RuleResult.fromFailed(nextRule, appConfig.showFailedAppData, unmatched) :: failed)
}
}
}
analyzePayloadRec(actionRules.reverse)(Nil, Nil, Nil).toInspectorReport // todo: if the analyzeModes are not Default - consider use Streams for lazy collection
}
Performance:
Until 22:16, this tailrec analyze was in use, then, the above code.
which you can see that generates much better performance - the same data was in use.
The x-axis is timeline and y-axis is time in ms (1.4s)
Any ideas why? tailrec should be faster, that's why I consider using foldRight.
What makes your tailrec version slow is
isCompleted(succeed.size, notApplicable.size, failed.size)
taking the size of a linked list in Scala is linear in the size, and you're computing the size of all three lists (at least two of which you're never using (and you don't use any of them by Default)).
On the nth iteration of the tailrec, you're going to walk n list nodes between the size computations, so n iterations of tailrec is at least O(n^2).
Passing the lists themselves to isCompleted (as you effectively do in the foldLeft version) and checking isEmpty should dramatically speed things up (especially in the Default case).
Assuming we have those case classes:
case class InspectorReport(succeed: List[ActionRule], notApplicable: List[ActionRule], failed: List[ActionRule])
case class ActionRule()
case class EvalResult(success: Boolean, missing: List[String], unmatched: List[String])
And the evaluator:
class ActionRuleService {
def eval(actionRule: ActionRule, payload: JsObject): EvalResult = EvalResult(true, List(), List())
}
val actionRuleService = new ActionRuleService
I would try something like this:
def analyzePayload(payload: JsObject, actionRules: List[ActionRule]): InspectorReport = {
val evaluated = actionRules.map(actionRule => (actionRule, actionRuleService.eval(actionRule, payload)))
val (success, failed) = evaluated.partition(_._2.success)
val (missing, unmatched) = failed.partition(_._2.missing.nonEmpty)
InspectorReport(success.map(_._1), missing.map(_._1), unmatched.map(_._1))
}
Or:
def analyzePayload(payload: JsObject, actionRules: List[ActionRule]): InspectorReport = {
val evaluated = actionRules.map(actionRule => (actionRule, actionRuleService.eval(actionRule, payload)))
val success = evaluated.collect {
case (actionRule, EvalResult(true, _, _)) =>
actionRule
}
val missing = evaluated.collect {
case (actionRule, EvalResult(false, missing, _)) if missing.nonEmpty =>
actionRule
}
val unmatched = evaluated.collect {
case (actionRule, EvalResult(false, missing, unmatched)) if missing.isEmpty && unmatched.nonEmpty =>
actionRule
}
InspectorReport(success, missing, unmatched)
}

How to make tree mapping tail-recursive?

Suppose I have a tree data structure like this:
trait Node { val name: String }
case class BranchNode(name: String, children: List[Node]) extends Node
case class LeafNode(name: String) extends Node
Suppose also I've got a function to map over leaves:
def mapLeaves(root: Node, f: LeafNode => LeafNode): Node = root match {
case ln: LeafNode => f(ln)
case bn: BranchNode => BranchNode(bn.name, bn.children.map(ch => mapLeaves(ch, f)))
}
Now I am trying to make this function tail-recursive but having a hard time to figure out how to do it. I've read this answer but still don't know to make that binary tree solution work for a multiway tree.
How would you rewrite mapLeaves to make it tail-recursive?
"Call stack" and "recursion" are merely popular design patterns that later got incorporated into most programming languages (and thus became mostly "invisible"). There is nothing that prevents you from reimplementing both with heap data structures. So, here is "the obvious" 1960's TAOCP retro-style solution:
trait Node { val name: String }
case class BranchNode(name: String, children: List[Node]) extends Node
case class LeafNode(name: String) extends Node
def mapLeaves(root: Node, f: LeafNode => LeafNode): Node = {
case class Frame(name: String, mapped: List[Node], todos: List[Node])
#annotation.tailrec
def step(stack: List[Frame]): Node = stack match {
// "return / pop a stack-frame"
case Frame(name, done, Nil) :: tail => {
val ret = BranchNode(name, done.reverse)
tail match {
case Nil => ret
case Frame(tn, td, tt) :: more => {
step(Frame(tn, ret :: td, tt) :: more)
}
}
}
case Frame(name, done, x :: xs) :: tail => x match {
// "recursion base"
case l # LeafNode(_) => step(Frame(name, f(l) :: done, xs) :: tail)
// "recursive call"
case BranchNode(n, cs) => step(Frame(n, Nil, cs) :: Frame(name, done, xs) :: tail)
}
case Nil => throw new Error("shouldn't happen")
}
root match {
case l # LeafNode(_) => f(l)
case b # BranchNode(n, cs) => step(List(Frame(n, Nil, cs)))
}
}
The tail-recursive step function takes a reified stack with "stack frames". A "stack frame" stores the name of the branch node that is currently being processed, a list of child nodes that have already been processed, and the list of the remaining nodes that still must be processed later. This roughly corresponds to an actual stack frame of your recursive mapLeaves function.
With this data structure,
returning from recursive calls corresponds to deconstructing a Frame object, and either returning the final result, or at least making the stack one frame shorter.
recursive calls correspond to a step that prepends a Frame to the stack
base case (invoking f on leaves) does not create or remove any frames
Once one understands how the usually invisible stack frames are represented explicitly, the translation is straightforward and mostly mechanical.
Example:
val example = BranchNode("x", List(
BranchNode("y", List(
LeafNode("a"),
LeafNode("b")
)),
BranchNode("z", List(
LeafNode("c"),
BranchNode("v", List(
LeafNode("d"),
LeafNode("e")
))
))
))
println(mapLeaves(example, { case LeafNode(n) => LeafNode(n.toUpperCase) }))
Output (indented):
BranchNode(x,List(
BranchNode(y,List(
LeafNode(A),
LeafNode(B)
)),
BranchNode(z, List(
LeafNode(C),
BranchNode(v,List(
LeafNode(D),
LeafNode(E)
))
))
))
It might be easier to implement it using a technique called trampoline.
If you use it, you'd be able to use two functions calling itself doing mutual recursion (with tailrec, you are limited to one function). Similarly to tailrec this recursion will be transformed to plain loop.
Trampolines are implemented in scala standard library in scala.util.control.TailCalls.
import scala.util.control.TailCalls.{TailRec, done, tailcall}
def mapLeaves(root: Node, f: LeafNode => LeafNode): Node = {
//two inner functions doing mutual recursion
//iterates recursively over children of node
def iterate(nodes: List[Node]): TailRec[List[Node]] = {
nodes match {
case x :: xs => tailcall(deepMap(x)) //it calls with mutual recursion deepMap which maps over children of node
.flatMap(node => iterate(xs).map(node :: _)) //you can flat map over TailRec
case Nil => done(Nil)
}
}
//recursively visits all branches
def deepMap(node: Node): TailRec[Node] = {
node match {
case ln: LeafNode => done(f(ln))
case bn: BranchNode => tailcall(iterate(bn.children))
.map(BranchNode(bn.name, _)) //calls mutually iterate
}
}
deepMap(root).result //unwrap result to plain node
}
Instead of TailCalls you could also use Eval from Cats or Trampoline from scalaz.
With that implementation function worked without problems:
def build(counter: Int): Node = {
if (counter > 0) {
BranchNode("branch", List(build(counter-1)))
} else {
LeafNode("leaf")
}
}
val root = build(4000)
mapLeaves(root, x => x.copy(name = x.name.reverse)) // no problems
When I ran that example with your implementation it caused java.lang.StackOverflowError as expected.

Find person and immediate neighbours in Seq[Person]

Given a Seq[Person], which contains 1-n Persons (and the minimum 1 Person beeing "Tom"), what is the easiest approach to find a Person with name "Tom" as well as the Person right before Tome and the Person right after Tom?
More detailed explanation:
case class Person(name:String)
The list of persons can be arbitrarily long, but will have at least one entry, which must be "Tom". So those lists can be a valid case:
val caseOne = Seq(Person("Tom"), Person("Mike"), Person("Dude"),Person("Frank"))
val caseTwo = Seq(Person("Mike"), Person("Tom"), Person("Dude"),Person("Frank"))
val caseThree = Seq(Person("Tom"))
val caseFour = Seq(Person("Mike"), Person("Tom"))
You get the idea. Since I already have "Tom", the task is to get his left neighbour (if it exists), and the right neighbour (if it exists).
What is the most efficient way to achieve to do this in scala?
My current approach:
var result:Tuple2[Option[Person], Option[Person]] = (None,None)
for (i <- persons.indices)
{
persons(i).name match
{
case "Tom" if i > 0 && i < persons.size-1 => result = (Some(persons(i-1)), Some(persons(i+1))) // (...), left, `Tom`, right, (...)
case "Tom" if i > 0 => result = (Some(persons(i-1)), None) // (...), left, `Tom`
case "Tom" if i < persons.size-1 => result = (Some(persons(i-1)), None) // `Tom`, right, (...)
case "Tom" => result = (None, None) // `Tom`
}
}
Just doesn't feel like I am doing it the scala way.
Solution by Mukesh prajapati:
val arrayPersons = persons.toArray
val index = arrayPersons.indexOf(Person("Tom"))
if (index >= 0)
result = (arrayPersons.lift(index-1), arrayPersons.lift(index+1))
Pretty short, seems to cover all cases.
Solution by anuj saxena
result = persons.sliding(3).foldLeft((Option.empty[Person], Option.empty[Person]))
{
case ((Some(prev), Some(next)), _) => (Some(prev), Some(next))
case (_, prev :: Person(`name`) :: next :: _) => (Some(prev), Some(next))
case (_, _ :: prev :: Person(`name`) :: _) => (Some(prev), None)
case (_, Person(`name`) :: next :: _) => (None, Some(next))
case (neighbours, _) => neighbours
}
First find out index where "Tom" is present, then use "lift". "lift" turns partial function into a plain function returning an Option result:
index = persons.indexOf("Tom")
doSomethingWith(persons.lift(index-1), persons.lift(index+1))
A rule of thumb: we should never access the content of a list / seq using indexes as it is prone to errors (like IndexNotFoundException).
If we want to use indexes, we better use Array as it provides us random access.
So to the current solution, here is my code to find prev and next element of a certain data in a Seq or List:
def findNeighbours(name: String, persons: Seq[Person]): Option[(Person, Person)] = {
persons.sliding(3).flatMap{
case prev :: person :: next :: Nil if person.name == name => Some(prev, next)
case _ => None
}.toList.headOption
}
Here the return type is in Option because there is a possibility that we may not find it here (in case of only one person is in the list or the required person is not in the list).
This code will pick the pair on the first occurrence of the person provided in the parameter.
If you have a probability that there might be several occurrences for the provided person, remove the headOption in the last line of the function findNeighbours. Then it will return a List of tuples.
Update
If Person is a case class then we can use deep match like this:
def findNeighbours(name: String, persons: Seq[Person]): Option[(Person, Person)] = {
persons.sliding(3).flatMap{
case prev :: Person(`name`) :: next :: Nil => Some(prev, next)
case _ => None
}.toList.headOption
}
For your solution need to add more cases to it (cchanged it to use foldleft in case of a single answer):
def findNeighboursV2(name: String, persons: Seq[Person]): (Option[Person], Option[Person]) = {
persons.sliding(3).foldLeft((Option.empty[Person], Option.empty[Person])){
case ((Some(prev), Some(next)), _) => (Some(prev), Some(next))
case (_, prev :: Person(`name`) :: next :: _) => (Some(prev), Some(next))
case (_, _ :: prev :: Person(`name`) :: _) => (Some(prev), None)
case (_, Person(`name`) :: next :: _) => (None, Some(next))
case (neighbours, _) => neighbours
}
}
You can use sliding function:
persons: Seq[Person] = initializePersons()
persons.sliding(size = 3).find { itr =>
if (itr(1).name = "Tom") {
val before = itr(0)
val middle = itr(1)
val after = itr(2)
}
}
If you know that there will be only one instance of "Tom" in your Seq use indexOf instead of looping by hand:
tomIndex = persons.indexOf("Tom")
doSomethingWith(persons(tomIndex-1), persons(tomIndex+1))
// Start writing your ScalaFiddle code here
case class Person(name: String)
val persons1 = Seq(Person("Martin"),Person("John"),Person("Tom"),Person("Jack"),Person("Mary"))
val persons2 = Seq(Person("Martin"),Person("John"),Person("Tom"))
val persons3 = Seq(Person("Tom"),Person("Jack"),Person("Mary"))
val persons4 = Seq(Person("Tom"))
def f(persons:Seq[Person]) =
persons
.sliding(3)
.filter(_.contains(Person("Tom")))
.maxBy {
case _ :: Person("Tom") :: _ => 1
case _ => 0
}
.toList
.take(persons.indexOf(Person("Tom")) + 2) // In the case where "Tom" is first, drop the last person
.drop(persons.indexOf(Person("Tom")) - 1) // In the case where "Tom" is last, drop the first person
println(f(persons1)) // List(Person(John), Person(Tom), Person(Jack))
println(f(persons2)) // List(Person(John), Person(Tom))
println(f(persons3)) // List(Person(Tom), Person(Jack))
println(f(persons4)) // List(Person(Tom))
Scalafiddle

Modifying Node tree in Scala

I have a node tree:
val root = Node("a", List(Node("w", Nil), Node("b", List(Node("c", List(Node("d", Nil))), Node("m", List(Node("n", Nil)))))))
and list of intermediate nodes:
val ks = List("b", "m")
that leads me to where which I have to add a node:
val child = Node("t", Nil)
that results in:
val res = Node("a", List(Node("w", Nil), Node("b", List(Node("c", List(Node("d", Nil))), Node("m", List(Node("n", Nil), Node("t", Nil)))))))
Tree in Scala is modeled as:
sealed trait Tree[A]
case class Empty[A]() extends Tree[A]
case class Node[A](rootNode: A, subtree: List[Tree[A]]) extends Tree[A]
I have made an attempt to traverse the tree and add the node like so,
#tailrec
def traverseAndAdd(root: Node[String], subNode: Node[String], child: Node[String], ls: List[String]): Node[String] = ls match {
case Nil =>
root
case x :: Nil =>
val k = subNode.subtree.filter(l => l.asInstanceOf[Node[String]].rootNode == x).head.asInstanceOf[Node[String]].subtree :+ child
println(k)
traverseAndAdd(root, subNode, child, Nil)
case x :: xs =>
traverseAndAdd(root, subNode.subtree.filter(l => l.asInstanceOf[Node[String]].rootNode == x).head.asInstanceOf[Node[String]], child, xs)
}
val root = Node("a", List(Node("w", Nil), Node("b", List(Node("c", List(Node("d", Nil))), Node("m", List(Node("n", Nil)))))))
val child = Node("t", Nil)
val ks = List("b", "m")
println("res: " + traverseAndAdd(root, root, child, ks))
I understand that here the list is immutable and even the code doesn't make any attempt to build the node ground up. I am asking for a suggestion on how can I achieve such a thing in Scala. Please help.
Also, I have already attempted the problem to which this problem is a sub problem using normal (not tail) recursion but I ended up with stackoverflow for the data is that huge. So thought of this approach!
I noticed a few shortcomings in your code.
class Empty is defined but never used.
val k is populated but never used.
Your data structure does not require uniqueness so a given Node path is not guaranteed to be unique.
Here's what I was able to construct. It's not tail recursive, nor does it address the uniqueness issue, but it appears to work.
case class Node[A](elem: A, subNodes: List[Node[A]])
def addNode[T](node: Node[T], path: List[T]): Node[T] = {
if (path.isEmpty)
node
else if (path.head == node.elem)
addNode(node, path.tail)
else if (node.subNodes.map(_.elem).contains(path.head))
Node(node.elem, node.subNodes.map{n =>
if (n.elem == path.head) addNode(n,path.tail)
else n
})
else
Node(node.elem
,node.subNodes :+ addNode(Node(path.head, List[Node[T]]()), path.tail))
}
val root = Node("a", List(Node("w", Nil)
,Node("b", List(Node("c", List(Node("d", Nil)))
,Node("m", List(Node("n", Nil)))))))
addNode(root,List("a","b","m","n","t"))

Split a list into a target element, and the rest of the list?

Let's say I have something like the following:
case class Thing(num: Int)
val xs = List(Thing(1), Thing(2), Thing(3))
What I'd like to do is separate the list into one particular value, and the rest of the list. The target value can be at any position in the list, or may not be present at all. The single value needs to be handled separately, after the other values are handled, so I can't simply use pattern matching.
What I have so far is this:
val (targetList, rest) = xs.partition(_.num == 2)
val targetEl = targetList match {
case x :: Nil => x
case _ => null
}
Is it possible to combine the two steps? Like
val (targetEl, rest) = xs.<some_method>
A note on handling order:
The reason that the target element must be handled last is that this is for use in a HTML template (Play framework). The other elements are looped through, and a HTML element is rendered for each. After that group of elements, another HTML element is created for the target element.
You can do it with pattern-matching in map, you just need multiple cases:
xs map {
case t # Thing(1) => // do something with thing 1
case t => // do something with the other things
}
To handle the OP's extra requirements:
xs map {
case t # Thing(num) if(num != 1) => // do something with things that are not "1"
case t => // do something with thing 1
}
Following produces two lists as tuples for some condition.
case class Thing(num: Int)
val xs = List(Thing(1), Thing(2), Thing(3))
val partioned = xs.foldLeft((List.empty[Thing], List.empty[Thing]))((x, y) => y match {
case t # Thing(1) => (x._1, t :: x._2)
case t => (t :: x._1, x._2)
})
//(List(Thing(3), Thing(2)),List(Thing(1)))
Try this:
val (targetEl, rest) = (xs.head, xs.tail)
It works for non-empty list. Nil case must be handled separately.
After some experimentation, I've come up with the following, which is almost what I'm looking for:
var (maybeTargetEl, rest) = xs
.foldLeft((Option.empty[Thing], List[Thing]())) { case ((opt, ls), x) =>
if (x.num == 1)
(Some(x), ls)
else
(opt, x :: ls)
}
The target value is still wrapped in a container, but at least it guarantees a single value.
After that I can do
rest map <some_method>
maybeTargetEl map <some_other_method>
If the order of the original list is important:
var (maybeTargetEl, rest) = xs.
foldLeft((Option.empty[Thing], ListBuffer[Thing]())){ case ((opt, lb), x) =>
if (x.num == 1)
(Some(x), ls)
else
(opt, lb += x)
} match {
case (opt, lb) => (opt, lb.toList)
}
#evanjdooner Your solution with fold works if target element is present only once. If you want to extract only one occurrence of target element:
def find(xs: List[T], target: T, prefix: List[T]) = xs match {
case target :: tail => (target, prefix ::: tail)
case other :: tail => find(tail, target, other :: prefix)
case Nil => throw new Exception("Not found")
}
val (el, rest) = find(xs, target, Nil)
Sorry, I can't add it as a comment.