我试图编写一个算法来检查列表中是否存在对象。
我的案例类如下:
case class Person(id:Int, name:String, friends:List[Person] = Nil)
我使用此代码编写了它:
@tailrec
final def find(id: Int, tree: List[Person]):Option[Person] = tree match {
case Nil => None
case (h :: t) => if(h.id == id) Option(h) else find(key, t ::: h.friends)
}
这是一个好方法吗?使用tail递归并在尾部列表中附加另一个列表?如果不是,最好的方法是什么?
答案 0 :(得分:1)
我最终得到了以下实现,基本上尾递归BFS :
@tailrec
def find(id: Int, level: List[Person], visited: Set[Person] = Set.empty): Option[Person] =
if (level.isEmpty) None
else {
// Try to find person on this level
val found = level.find(_.id == id).filterNot(visited.contains)
if (found.isDefined) found
else find(
id,
// Next level construction
level.flatMap(_.friends).distinct,
// Keep track of visited to handle cycles
visited ++ level
)
}
更新:另外,我建议按名称添加呼叫,以便能够使用更多测试用例:
class Person(val id: Int, val name: String, friends: => List[Person]) {
def friendList = friends
override def toString = name
}
object Person {
def apply(id: Int, name: String, friends: => List[Person] = Nil) = new Person(id, name, friends)
}
在这种情况下,您可以从评论中撰写示例:
val john = Person(1, "john")
val russ = Person(2, "russ")
val bob = Person(3, "bob")
val lois = Person(5, "lois")
lazy val `eve friends` = List(john, anne)
lazy val `peter friends` = List(eve, bob, russ)
lazy val `anne friends` = List(peter, lois)
val eve = Person(7, "eve", `eve friends`)
val peter = Person(8, "peter", `peter friends`)
val anne: Person = Person(6, "anne", `anne friends`)
println(find(8, List(eve, peter, lois))) // result: Some(peter)