Я пытаюсь понять, как использовать scalaz State
] для выполнения сложных вычислений с отслеживанием состояния. Вот проблема:
Учитывая
Список [Int]
потенциальных делителей иСписок [Int]
чисел, найдите] Список [(Int, Int)
] совпадающих пар (делитель, число), где делителю разрешено совпадать не более одного числа.
В качестве теста:
def findMatches(divs: List[Int], nums: List[Int]): List[(Int, Int)]
И с следующий ввод:
findMatches( List(2, 3, 4), List(1, 6, 7, 8, 9) )
Мы можем получить не более трех совпадений. Если мы оговорим, что совпадения должны выполняться в том порядке, в котором они происходят при обходе списков lr, тогда совпадения должны быть:
List( (2, 6) , (3, 9) , (4, 8) )
] Итак, следующие два теста должны пройти:
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)))
Вот обязательное решение:
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)]
Обратите внимание, что мне нужно обновить состояние оставшихся
, а также накопить совпадений
. звучит как работа для скалярного траверса!
Моя бесполезная работа завела меня так далеко:
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)]) }
^