This is a simple exercise I am solving in Scala: given a list l return a new list, which contains every n-th element of l. If n > l.size return an empty list.
def skip(l: List[Int], n: Int) =
Range(1, l.size/n + 1).map(i => l.take(i * n).last).toList
My solution (see above) seem to work but I am looking for smth. simpler. How would you simplify it?
Somewhat simpler:
scala> val l = (1 to 10).toList
l: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// n == 3
scala> l.drop(2).grouped(3).map(_.head).toList
res0: List[Int] = List(3, 6, 9)
// n > l.length
scala> l.drop(11).grouped(12).map(_.head).toList
res1: List[Int] = List()
(the toList just to force the iteratot to be evaluated)
Works with infinite lists:
Stream.from(1).drop(2).grouped(3).map(_.head).take(4).toList
res2: List[Int] = List(3, 6, 9, 12)
scala> def skip[A](l:List[A], n:Int) =
l.zipWithIndex.collect {case (e,i) if ((i+1) % n) == 0 => e} // (i+1) because zipWithIndex is 0-based
skip: [A](l: List[A], n: Int)List[A]
scala> val l = (1 to 10).toList
l: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> skip(l,3)
res2: List[Int] = List(3, 6, 9)
scala> skip(l,11)
res3: List[Int] = List()
A bit more readable and the loop size is O(l.length/n):
def skip(l: List[Int], n: Int) = {
require(n > 0)
for (step <- Range(start = n - 1, end = l.length, step = n))
yield l(step)
}
Fold left approach O(n)
def skip(xs: List[Int], n: Int) = {
xs.foldLeft((List[Int](), n)){ case ((acc, counter), x) =>
if(counter==1)
(x+:acc,n)
else
(acc, counter-1)
}
._1
.reverse
}
scala > skip(List(1,2,3,4,5,6,7,8,9,10), 3)
Tailrec less readable approach O(n)
import scala.annotation.tailrec
def skipTR(xs: List[Int], n: Int) = {
#tailrec
def go(ys: List[Int], acc: List[Int], counter: Int): List[Int] = ys match {
case k::ks=>
if(counter==1)
go(ks, k+:acc , n)
else
go(ks, acc, counter-1)
case Nil => acc
}
go(xs, List(), n).reverse
}
skipTR(List(1,2,3,4,5,6,7,8,9,10), 3)
You could omit toList if you don't mind an iterator:
scala> def skip[A](l:List[A], n:Int) =
l.grouped(n).filter(_.length==n).map(_.last).toList
skip: [A](l: List[A], n: Int)List[A]
scala> skip (l,3)
res6: List[Int] = List(3, 6, 9)
Two approaches based in filter on indexes, as follows,
implicit class RichList[A](val list: List[A]) extends AnyVal {
def nthA(n: Int) = n match {
case 0 => List()
case _ => (1 to a.size).filter( _ % n == 0).map { i => list(i-1)}
}
def nthB(n: Int) = n match {
case 0 => List()
case _ => list.zip(Stream.from(1)).filter(_._2 % n == 0).unzip._1
}
}
and so for a given list
val a = ('a' to 'z').toList
we have that
a.nthA(5)
res: List(e, j, o, t, y)
a.nthA(123)
res: List()
a.nthA(0)
res: List()
Update
Using List.tabulate as follows,
implicit class RichList[A](val list: List[A]) extends AnyVal {
def nthC(n: Int) = n match {
case 0 => List()
case n => List.tabulate(list.size) {i =>
if ((i+1) % n == 0) Some(list(i))
else None }.flatten
}
}
Related
How to split an iterator into a prefix with duplicates and the rest ? For instance,
def splitDupes(it: Iterator[Int]): (Iterator[Int], Iterator[Int]) = ???
val (xs, ys) = splitDupes(List(1, 1, 1, 2, 3, 4, 5).iterator)
xs.toList // List(1, 1, 1)
ys.toList // List(2, 3, 4, 5)
val (xs, ys) = splitDupes(List(1, 2, 3, 4, 5).iterator)
xs.toList // List(1)
ys.toList // List(2, 3, 4, 5)
val (xs, ys) = splitDupes(List(1, 1, 1, 1, 1).iterator)
xs.toList // List(1, 1, 1, 1, 1)
ys.toList // List()
val (xs, ys) = splitDupes(List[Int]().iterator)
xs.toList // List()
ys.toList // List()
Can I use it to read a text file by chunks ?
You can use the span method to split an Iterable into a prefix that satisfies a predicate and a suffix that doesn't. For Iterators span does the correct thing, and lazily stores elements in the prefix Iterator, in case the suffix was iterated before the prefix has run out.
def splitDupes[T](it: Iterator[T]): (Iterator[T], Iterator[T]) = {
if (it.isEmpty) (Iterator.empty, Iterator.empty)
else {
val head = it.next()
val (dupes, rest) = it.span(_ == head)
(Iterator(head) ++ dupes, rest)
}
}
Example:
scala> val (dupes, rest) = splitDupes(Iterator(1,1,1,2,3,2,1))
dupes: Iterator[Int] = <iterator>
rest: Iterator[Int] = <iterator>
scala> (dupes.toList, rest.toList)
res1: (List[Int], List[Int]) = (List(1, 1, 1),List(2, 3, 2, 1))
What about something like this?
(Note: I decided to return a plain List as the first part since that would already been consumed)
def splitDupes[A](it: Iterator[A]): (List[A], Iterator[A]) = {
it.nextOption() match {
case Some(head) =>
#annotation.tailrec
def loop(count: Int): (List[A], Iterator[A]) =
it.nextOption() match {
case Some(x) if (x == head) =>
loop(count + 1)
case Some(x) =>
List.fill(count)(head) -> Iterator(Iterator.single(x), it).flatten
case None =>
List.fill(count)(head) -> Iterator.empty
}
loop(count = 1)
case None =>
List.empty -> Iterator.empty
}
}
I want to write a function which will add an element n to a list n times for all elements in an input list.
For example:
L = List(2,4,1)
Output should be:
List(2,2,4,4,4,4,1)
I would like to do it with tail recursion. So far, I have written this:
def repeat(numbers: List[Int]): List[Int] = {
def repeat_acc(numbers: List[Int], acc: List[Int], number_acc: Int): List[Int] = {
if (numbers.length == 0)
return acc
else if (number_acc == 0)
repeat_acc(numbers.tail, acc, numbers.head)
else
repeat_acc(numbers, acc :+ numbers.head, (number_acc-1))
}
repeat_acc(numbers, List(), 0)
}
The problem is that it leaves out the first element of the list. For this output will be:
(4, 4, 1, 1, 1, 1)
I know why it happens, but I cannot fix it. I have tried many other ways, but for me it seems that tail recursion do not work here. Some always goes wrong, and I get the wrong result.
Thanks for any advice.
I know you want to do a personalized tail recursive call, but I would recommend the following instead:
def repeat(numbers: List[Int]): List[Int] = {
numbers.flatMap(n => List.fill(n)(n))
}
The inner function takes the value n and repeats it n times in a list, and then this function is flat mapped onto the original list (a regular map would turn List(1,2,3) into List(List(1), List(2, 2), List(3, 3, 3)), so we use flat map). This has the benefit of 'doing it the Scala way' with built in collections functionality.
This problem gets a lot simpler if you add another parameter to your inner recursive method, representing the current number being added. You should also familiarize yourself with match statements, since they are really powerful in Scala and can help express exactly this type of logic. Nested if/else statements and early return statements are considered unidiomatic. Try:
def repeat(numbers: List[Int]) = {
def repeatAcc(acc: List[Int], curr: Int, rem: Int, numbers:List[Int]): List[Int] =
(numbers, rem) match {
case (Nil, 0) => acc
case (hd::tl, 0) => repeatAcc(acc, hd, hd, tl)
case (_, n) => repeatAcc(acc :+ curr, curr, n - 1, numbers)
}
repeatAcc(List.empty[Int], 0, 0, numbers)
}
You might also try to use some standard Scala methods like List.fill, which can be used in conjunction with the tail recursion as follows:
def repeat(numbers: List[Int]) = {
def repeatAcc(acc: List[Int], numbers:List[Int]): List[Int] = numbers match {
case hd::tl => repeatAcc(acc ++ List.fill(hd)(hd), tl)
case Nil => acc
}
repeatAcc(List.empty[Int], numbers)
}
Finally, I understand you're trying to learn about these core concepts, but it should be mentioned that this is really simple with Scala built ins:
(List.empty[Int] /: numbers) { case (soFar, next) => soFar ++ List.fill(next)(next) }
numbers.flatMap(x => List.fill(x)(x))
Try this, it works
import scala.annotation.tailrec
#tailrec
def f(l: List[Int], res: List[Int] = Nil): List[Int] = {
#tailrec
def g(n: Int, acc: List[Int]): List[Int] = {
if (n == 1) acc
else g(n - 1, acc :+ acc.head)
}
if (l == Nil) res else f(l.tail, res ++ g(l.head, List(l.head)))
}
scala> f(List(1,2,3))
res0: List[Int] = List(1, 2, 2, 3, 3, 3)
Ok, I find the solution. Looks bad, but works. I'm too tired to figure out something better.
Here is my code:
def repeat(numbers: List[Int]): List[Int] = {
def repeat_acc(numbers: List[Int], acc: List[Int], number_acc: Int): List[Int] = {
if (numbers.length == 1 && number_acc == 0)
return acc
else if (acc.length == 0)
repeat_acc(numbers, acc :+ numbers.head, (number_acc-1))
else if (number_acc == 0 && numbers.tail != Nil ){
repeat_acc(numbers.tail, acc, (numbers.tail.head))
}
else
repeat_acc(numbers, acc :+ numbers.head, (number_acc-1))
}
repeat_acc(numbers, List(), numbers.head)
}
simple, just use fill + flatMap
val result = L.flatMap(x => List.fill(x)(x))
for recursive solution :
scala> def repeat(numbers: List[Int]): List[Int] = {
def run(nums:List[Int]):List[Int] ={
nums match {
case Nil => List.empty[Int]
case x::Nil => List.fill(x)(x)
case x::xs => List.fill(x)(x):::run(xs)
}}
run(numbers)
}
scala> repeat(List(2,4,1))
res1: List[Int] = List(2, 2, 4, 4, 4, 4, 1)
I want to split a list of elements into a list of lists such that neighboring elements in the inner list satisfy a given condition.
A simple condition would be neighboring elements are equal. Then if the input is List(1,1,1,2,2,3,3,3,3) output is List(List(1,1,1),List(2,2),List(3,3,3)).
Another condition could be current element should be greater than prev element. Then if the input is List(1,2,3,1,4,6,5,7,8), the output is List(List(1,2,3), List(1,4,6), List(5,7,8)). It would also be wonderful if the method can act on Iterator. The typedef of the method is
def method[A](lst:List[A], cond:(A,A)=>Boolean):List[List[A]]
def method[A](lst:Iterator[A], cond:(A,A)=>Boolean):Iterator[Iterator[A]]
You can use sliding together with span in a recursive function for the desired effect. This quick and dirty version is less efficient, but terser than some of the alternative:
def method[A](lst: TraversableOnce[A], cond: (A, A) => Boolean): List[List[A]] = {
val iterable = lst.toIterable
iterable.headOption.toList.flatMap { head =>
val (next, rest) = iterable.sliding(2).filter(_.size == 2).span(x => cond(x.head, x.last))
(head :: next.toList.map(_.last)) :: method(rest.map(_.last), cond)
}
}
If you want to lazily execute the code, you can return an Iterator[List[A]] instead of List[List[A]]:
def method[A](lst: TraversableOnce[A], cond: (A, A) => Boolean): Iterator[List[A]] = {
val iterable = lst.toIterable
iterable.headOption.toIterator.flatMap { head =>
val (next, rest) = iterable.sliding(2).filter(_.size == 2).span(x => cond(x.head, x.last))
Iterator(head :: next.toList.map(_.last)) ++ method(rest.map(_.last), cond)
}
}
And you can verify that this is lazy:
val x = (Iterator.range(0, 10) ++ Iterator.range(3, 5) ++ Iterator.range(1, 3)).map(x => { println(x); x })
val iter = method(x, (x: Int, y: Int) => x < y) //Only prints 0-9, and then 3!
iter.take(2).toList //Prints more
iter.toList //Prints the rest
You can make it even lazier by returning an Iterator[Iterator[A]]:
def method[A](lst: TraversableOnce[A], cond: (A, A) => Boolean): Iterator[Iterator[A]] = {
val iterable = lst.toIterable
iterable.headOption.toIterator.flatMap { head =>
val (next, rest) = iterable.sliding(2).filter(_.size == 2).span(x => cond(x.head, x.last))
Iterator(Iterator(head) ++ next.toIterator.map(_.last)) ++ method(rest.map(_.last), cond)
}
}
As a relatively unrelated side note, when you have generic parameters of this form, you're better off using 2 parameter lists:
def method[A](lst: TraversableOnce[A])(cond: (A, A) => Boolean)
When you have 2 parameter lists like this, the type inference can be a little bit smarter:
//No need to specify parameter types on the anonymous function now!
method(List(1, 3, 2, 3, 4, 1, 8, 1))((x, y) => x < y).toList
//You can now even use underscore anonymous function notation!
method(List(1, 4, 2, 3, 4, 1, 8))(_ < _)
Here is something close (I believe) to what you are asking for. The only issue with this is that it always produces a List of Lists for the result as opposed to being based on the input type:
val iter = Iterator(1,1,2,2,2,3,3,3)
val list = List(4,5,5,5,5,6,6)
def same(a:Int,b:Int) = a == b
def gt(a:Int, b:Int) = b > a
println(groupByPred(iter, same))
println(groupByPred(list, gt))
def groupByPred[L <: TraversableOnce[T], T](trav:L, cond:(T,T) => Boolean):List[List[T]] = {
val (ret, inner) =
trav.foldLeft((List.empty[List[T]], List.empty[T])){
case ((acc, list), el) if list.isEmpty || cond(list.head, el) => (acc,el :: list)
case ((acc, list), el) => (list.reverse :: acc,el :: List.empty)
}
(inner.reverse :: ret).reverse
}
If you run that code, the output should be the following:
List(List(1, 1), List(2, 2, 2), List(3, 3, 3))
List(List(4, 5), List(5), List(5), List(5, 6), List(6))
Try this.
Puts the head of the list as the first element of the first element of the List of Lists. Then adds things to that first List if the condition holds. If it doesn't, starts a new List with the current entry as the first element.
Both the inner list and the outer are constructed in the wrong order. So reverse each element of the outer List (with map) and then reverse the outer list.
val xs = List(1, 1, 1, 2, 2, 3, 3, 3, 3)
val ys = List(1, 2, 3, 1, 4, 6, 5, 7, 8)
def method[A](lst: List[A], cond: (A, A) => Boolean): List[List[A]] = {
lst.tail.foldLeft(List(List(lst.head))) { (acc, e) =>
if (cond(acc.head.head, e))
(e :: acc.head) :: acc.tail
else List(e) :: acc
}.map(_.reverse).reverse
}
method(xs, { (a: Int, b: Int) => a == b })
//> res0: List[List[Int]] = List(List(1, 1, 1), List(2, 2), List(3, 3, 3, 3))
method(ys, { (a: Int, b: Int) => a < b })
//> res1: List[List[Int]] = List(List(1, 2, 3), List(1, 4, 6), List(5, 7, 8))
Iterator overload
def method[A](iter:Iterator[A], cond: (A, A) => Boolean): List[List[A]] = {
val h = iter.next
iter.foldLeft(List(List(h))) { (acc, e) =>
if (cond(acc.head.head, e))
(e :: acc.head) :: acc.tail
else List(e) :: acc
}.map(_.reverse).reverse
}
method(xs.toIterator, { (a: Int, b: Int) => a == b })
//> res0: List[List[Int]] = List(List(1, 1, 1), List(2, 2), List(3, 3, 3, 3))
method(ys.toIterator, { (a: Int, b: Int) => a < b })
//> res1: List[List[Int]] = List(List(1, 2, 3), List(1, 4, 6), List(5, 7, 8))
More generic version (hat-tip to #cmbaxter for some ideas here) that works with Lists, Iterators and anything that can be traversed once:
def method[A, T <: TraversableOnce[A]](trav: T, cond: (A, A) => Boolean)
: List[List[A]] = {
trav.foldLeft(List(List.empty[A])) { (acc, e) =>
if (acc.head.isEmpty || !cond(acc.head.head, e)) List(e) :: acc
else (e :: acc.head) :: acc.tail
}.map(_.reverse).reverse
}
Suppose there is a List[A] and two predicates p1: A => Boolean and p2: A => Boolean.
I need to find two elements in the list: the first element a1 satisfying p1 and the first element a2 satisfying p2 (in my case a1 != a2)
Obviously, I can run find twice but I would like to do it in one pass. How would you do it in one pass in Scala ?
So, here's an attempt. It's fairly straightforward to generalise it to take a list of predicates (and return a list of elements found)
def find2[A](xs: List[A], p1: A => Boolean, p2: A => Boolean): (Option[A], Option[A]) = {
def find2helper(xs: List[A], p1: A => Boolean, p2: A => Boolean, soFar: (Option[A], Option[A])): (Option[A], Option[A]) = {
if (xs == Nil) soFar
else {
val a1 = if (soFar._1.isDefined) soFar._1 else if (p1(xs.head)) Some(xs.head) else None
val a2 = if (soFar._2.isDefined) soFar._2 else if (p2(xs.head)) Some(xs.head) else None
if (a1.isDefined && a2.isDefined) (a1, a2) else find2helper(xs.tail, p1, p2, (a1, a2))
}
}
find2helper(xs, p1, p2, (None, None))
} //> find2: [A](xs: List[A], p1: A => Boolean, p2: A => Boolean)(Option[A], Option[A])
val foo = List(1, 2, 3, 4, 5) //> foo : List[Int] = List(1, 2, 3, 4, 5)
find2[Int](foo, { x: Int => x > 2 }, { x: Int => x % 2 == 0 })
//> res0: (Option[Int], Option[Int]) = (Some(3),Some(2))
find2[Int](foo, { x: Int => x > 2 }, { x: Int => x % 7 == 0 })
//> res1: (Option[Int], Option[Int]) = (Some(3),None)
find2[Int](foo, { x: Int => x > 7 }, { x: Int => x % 2 == 0 })
//> res2: (Option[Int], Option[Int]) = (None,Some(2))
find2[Int](foo, { x: Int => x > 7 }, { x: Int => x % 7 == 0 })
//> res3: (Option[Int], Option[Int]) = (None,None)
Generalised version (which is actually slightly clearer, I think)
def findN[A](xs: List[A], ps: List[A => Boolean]): List[Option[A]] = {
def findNhelper(xs: List[A], ps: List[A => Boolean], soFar: List[Option[A]]): List[Option[A]] = {
if (xs == Nil) soFar
else {
val as = ps.zip(soFar).map {
case (p, e) => if (e.isDefined) e else if (p(xs.head)) Some(xs.head) else None
}
if (as.forall(_.isDefined)) as else findNhelper(xs.tail, ps, as)
}
}
findNhelper(xs, ps, List.fill(ps.length)(None))
} //> findN: [A](xs: List[A], ps: List[A => Boolean])List[Option[A]]
val foo = List(1, 2, 3, 4, 5) //> foo : List[Int] = List(1, 2, 3, 4, 5)
findN[Int](foo, List({ x: Int => x > 2 }, { x: Int => x % 2 == 0 }))
//> res0: List[Option[Int]] = List(Some(3), Some(2))
findN[Int](foo, List({ x: Int => x > 2 }, { x: Int => x % 7 == 0 }))
//> res1: List[Option[Int]] = List(Some(3), None)
findN[Int](foo, List({ x: Int => x > 7 }, { x: Int => x % 2 == 0 }))
//> res2: List[Option[Int]] = List(None, Some(2))
findN[Int](foo, List({ x: Int => x > 7 }, { x: Int => x % 7 == 0 }))
//> res3: List[Option[Int]] = List(None, None)
scala> val l = List(1,2,3)
l: List[Int] = List(1, 2, 3)
scala> val p1 = {x:Int => x % 2 == 0}
p1: Int => Boolean = <function1>
scala> val p2 = {x:Int => x % 3 == 0}
p2: Int => Boolean = <function1>
scala> val pp = {x:Int => p1(x) || p2(x) }
pp: Int => Boolean = <function1>
scala> l.find(pp)
res2: Option[Int] = Some(2)
scala> l.filter(pp)
res3: List[Int] = List(2, 3)
Does this work for you?
def predFilter[A](lst: List[A], p1: A => Boolean, p2: A => Boolean): List[A] =
lst.filter(x => p1(x) || p2(x)) // or p1(x) && p2(x) depending on your need
This will return you a new list that matches either of the predicates.
val a = List(1,2,3,4,5)
val b = predFilter[Int](a, _ % 2 == 0, _ % 3 == 0) // b is now List(2, 3, 4)
I'm trying to understand how to use scalaz State to perform a complicated stateful computation. Here is the problem:
Given a List[Int] of potential divisors and a List[Int] of numbers, find a List[(Int, Int)] of matching pairs (divisor, number) where a divisor is allowed to match at most one number.
As a test:
def findMatches(divs: List[Int], nums: List[Int]): List[(Int, Int)]
And with the following input:
findMatches( List(2, 3, 4), List(1, 6, 7, 8, 9) )
We can get at most 3 matches. If we stipulate that the matches must be made in the order in which they occur traversing the lists l-r, then the matches must be:
List( (2, 6) , (3, 9) , (4, 8) )
So the following two tests need to pass:
assert(findMatches(List(2, 3, 4), List(1, 6, 7, 8, 9)) == List((2, 6), (3, 9), (4, 8)))
assert(findMatches(List(2, 3, 4), List(1, 6, 7, 8, 11)) == List((2, 6), (4, 8)))
Here's an imperative solution:
scala> def findMatches(divs: List[Int], nums: List[Int]): List[(Int, Int)] = {
| var matches = List.empty[(Int, Int)]
| var remaining = nums
| divs foreach { div =>
| remaining find (_ % div == 0) foreach { n =>
| remaining = remaining filterNot (_ == n)
| matches = matches ::: List(div -> n)
| }
| }
| matches
| }
findMatches: (divs: List[Int], nums: List[Int])List[(Int, Int)]
Notice that I have to update the state of remaining as well as accumulating matches. It sounds like a job for scalaz traverse!
My useless working has got me this far:
scala> def findMatches(divs: List[Int], nums: List[Int]): List[(Int, Int)] = {
| divs.traverse[({type l[a] = State[List[Int], a]})#l, Int]( div =>
| state { (rem: List[Int]) => rem.find(_ % div == 0).map(n => rem.filterNot(_ == n) -> List(div -> n)).getOrElse(rem -> List.empty[(Int, Int)]) }
| ) ~> nums
| }
<console>:15: error: type mismatch;
found : List[(Int, Int)]
required: Int
state { (rem: List[Int]) => rem.find(_ % div == 0).map(n => rem.filterNot(_ == n) -> List(div -> n)).getOrElse(rem -> List.empty[(Int, Int)]) }
^
Your code only needs to be slightly modified in order to use State and Traverse:
// using scalaz-seven
import scalaz._
import Scalaz._
def findMatches(divs: List[Int], nums: List[Int]) = {
// the "state" we carry when traversing
case class S(matches: List[(Int, Int)], remaining: List[Int])
// initially there are no found pairs and a full list of nums
val initialState = S(List[(Int, Int)](), nums)
// a function to find a pair (div, num) given the current "state"
// we return a state transition that modifies the state
def find(div: Int) = modify((s: S) =>
s.remaining.find(_ % div == 0).map { (n: Int) =>
S(s.matches :+ div -> n, s.remaining -n)
}.getOrElse(s))
// the traversal, with no type annotation thanks to Scalaz7
// Note that we use `exec` to get the final state
// instead of `eval` that would just give us a List[Unit].
divs.traverseS(find).exec(initialState).matches
}
// List((2,6), (3,9), (4,8))
findMatches(List(2, 3, 4), List(1, 6, 7, 8, 9))
You can also use runTraverseS to write the traversal a bit differently:
divs.runTraverseS(initialState)(find)._2.matches
I have finally figured this out after much messing about:
scala> def findMatches(divs: List[Int], nums: List[Int]): List[(Int, Int)] = {
| (divs.traverse[({type l[a] = State[List[Int], a]})#l, Option[(Int, Int)]]( div =>
| state { (rem: List[Int]) =>
| rem.find(_ % div == 0).map(n => rem.filterNot(_ == n) -> Some(div -> n)).getOrElse(rem -> none[(Int, Int)])
| }
| ) ! nums).flatten
| }
findMatches: (divs: List[Int], nums: List[Int])List[(Int, Int)]
I think I'll be looking at Eric's answer for more insight into what is actually going on, though.
Iteration #2
Exploring Eric's answer using scalaz6
scala> def findMatches2(divs: List[Int], nums: List[Int]): List[(Int, Int)] = {
| case class S(matches: List[(Int, Int)], remaining: List[Int])
| val initialState = S(nil[(Int, Int)], nums)
| def find(div: Int, s: S) = {
| val newState = s.remaining.find(_ % div == 0).map { (n: Int) =>
| S(s.matches :+ div -> n, s.remaining filterNot (_ == n))
| }.getOrElse(s)
| newState -> newState.matches
| }
| val findDivs = (div: Int) => state((s: S) => find(div, s))
| (divs.traverse[({type l[a]=State[S, a]})#l, List[(Int, Int)]](findDivs) ! initialState).join
| }
findMatches2: (divs: List[Int], nums: List[Int])List[(Int, Int)]
scala> findMatches2(List(2, 3, 4), List(1, 6, 7, 8, 9))
res11: List[(Int, Int)] = List((2,6), (2,6), (3,9), (2,6), (3,9), (4,8))
The join on the List[List[(Int, Int)]] at the end is causing grief. Instead we can replace the last line with:
(divs.traverse[({type l[a]=State[S, a]})#l, List[(Int, Int)]](findDivs) ~> initialState).matches
Iteration #3
In fact, you can do away with the extra output of a state computation altogether and simplify even further:
scala> def findMatches2(divs: List[Int], nums: List[Int]): List[(Int, Int)] = {
| case class S(matches: List[(Int, Int)], remaining: List[Int])
| def find(div: Int, s: S) =
| s.remaining.find(_ % div == 0).map( n => S(s.matches :+ div -> n, s.remaining filterNot (_ == n)) ).getOrElse(s) -> ()
| (divs.traverse[({type l[a]=State[S, a]})#l, Unit](div => state((s: S) => find(div, s))) ~> S(nil[(Int, Int)], nums)).matches
| }
findMatches2: (divs: List[Int], nums: List[Int])List[(Int, Int)]
Iteration #4
modify described above by Apocalisp is also available in scalaz6 and removes the need to explicitly supply the (S, ()) pair (although you do need Unit in the type lambda):
scala> def findMatches2(divs: List[Int], nums: List[Int]): List[(Int, Int)] = {
| case class S(matches: List[(Int, Int)], remaining: List[Int])
| def find(div: Int) = modify( (s: S) =>
| s.remaining.find(_ % div == 0).map( n => S(s.matches :+ div -> n, s.remaining filterNot (_ == n)) ).getOrElse(s))
| (divs.traverse[({type l[a]=State[S, a]})#l, Unit](div => state(s => find(div)(s))) ~> S(nil, nums)).matches
| }
findMatches2: (divs: List[Int], nums: List[Int])List[(Int, Int)]
scala> findMatches2(List(2, 3, 4), List(1, 6, 7, 8, 9))
res0: List[(Int, Int)] = List((2,6), (3,9), (4,8))