Scala:元素列表中元素之间的递归搜索
如果我有这样一门课:Scala:元素列表中元素之间的递归搜索,scala,search,recursion,constraints,Scala,Search,Recursion,Constraints,如果我有这样一门课: class Person (var name:String, var surname:String, var sons: Set[Person]) 我想要一种控制,一个人不能在他的儿子和他的儿子之间控制自己。 我该怎么做 我曾想过递归搜索。但我必须小心不要创造循环。 我可以使用一个布尔值作为保护,只要你找到一个包含它自己的项,它就会停止搜索 我如何实现这一点?你有什么想法吗? 多谢各位 更新 非常感谢你的帮助。答案不错,但最重要的是你有很棒的想法。 现在我只需要最后一点帮
class Person (var name:String, var surname:String, var sons: Set[Person])
我想要一种控制,一个人不能在他的儿子和他的儿子之间控制自己。
我该怎么做
我曾想过递归搜索。但我必须小心不要创造循环。
我可以使用一个布尔值作为保护,只要你找到一个包含它自己的项,它就会停止搜索
我如何实现这一点?你有什么想法吗?
多谢各位
更新
非常感谢你的帮助。答案不错,但最重要的是你有很棒的想法。
现在我只需要最后一点帮助,在我的小项目上测试这个检查
我的真实情况如下:
trait ArchitecturalElement extends PropertyHolderElement with TypedElement{}
abstract class Component extends ConnectableElement with ArchitecturalElement {
var subElements : Set[ArchitecturalElement]
var interactionPoints : Set[InteractionPoint]
//Here I put the control
//A component cannot contain himself in his subElements and in subElements of it subelement
def notHerOwnDescendant = {
def notDescendant(ancestor: Component, current: Component, checked: Set[ArchitecturalElement]): Boolean =
!current.subElements.contains(ancestor) && current.subElements.forall(
p => checked.contains(p) || notDescendant(ancestor, p, checked + p))
notDescendant(this, this, Set())
}
}//Component
abstract class InteractionPoint extends ConnectableElement{}
class SAInterface( var name : String,
var description : String = "empty",
var direction : SAInterfaceDirection = null
)extends InteractionPoint with ArchitecturalElement
class SAComponent ( var name :String,
var description : String = "empty",
var subElements : Set[ArchitecturalElement] = Set(),
var interactionPoints : Set[InteractionPoint] = Set()
) extends Component
但我有一个不兼容的类型:
类型失配;找到:a0Dominio.ArchitecturalElement所需:a0Dominio.SAComponent
p => checked.contains(p) || notDescendant(ancestor, p, checked + p)
// ^ here
从集合[ArchitecturalElement]派生出集合[Component]?
组件继承自ArchitecturalElement。如果我理解正确,您需要这样的东西:
class Person (var name:String, var surname:String, var sons: Set[Person])
或者,如果你想一直往下走:
class Person(...) {
...
def notDescendant(person: Person) =
!sons.contains(person) && sons.forall(_.notDescendant(person))
def notHerOwnDescendant =
notDescendant(this)
...
}
免责声明:我无法在IDE中测试此代码,因此不能保证它编译正确。尽管如此,我希望它至少能成为思想的食粮:——)
更新
这是一个经过更新和测试的版本,它使用@gilad提到的“图形着色”解决方案处理循环:
class Person (val name:String, val surname:String, var sons: Set[Person]) {
def notHerOwnDescendant = {
def notDescendant(ancestor: Person, current: Person, checked: Set[Person]): Boolean =
!current.sons.contains(ancestor)
&& current.sons.forall(
p => checked.contains(p) || notDescendant(ancestor, p, checked + p))
notDescendant(this, this, Set())
}
}
一些测试代码:
val abel = new Person("", "Abel", Set())
val cain = new Person("", "Cain", Set())
val adam = new Person("", "Adam", Set(abel, cain))
println("Adam is not his own descendant: " + adam.notHerOwnDescendant)
cain.sons += cain
println("Added Cain to his sons' set")
println("Adam is not his own descendant: " + adam.notHerOwnDescendant)
abel.sons += adam
println("Added Adam to his grandsons' set")
println("Adam is not his own descendant: " + adam.notHerOwnDescendant)
以及输出:
Adam is not his own descendant: true
Added Cain to his sons' set
Adam is not his own descendant: true
Added Adam to his grandsons' set
Adam is not his own descendant: false
更简单的解决方案?
作为旁注,我相信只要坚持使用val
properties而不是var
s,就可以防止一个人成为自己的后代。如果子对象集
不可变,则无法在图形中创建循环,因为在创建父对象之前需要准备好子对象集
,并且无法将父对象添加到任何现有子对象集。请注意,我必须将sons
作为var
保存,以便编译上述测试代码
至少我是这么看的-但是可能有一些技巧可以克服这一点,例如使用我还不是很有经验的惰性评估。如果我错了,请有人纠正我
更新2
类型失配;找到:a0Dominio.ArchitecturalElement
必需:a0Dominio.SAComponent
我认为这里可能有一个输入错误:根据您方法的声明,SAComponent
应该是Component
不是吗
无论如何,问题是您将子元素
声明为集合[ArchitecturalElement]
,因此其元素显然属于ArchitecturalElement
类型,而不是组件
(继承关系则相反)。因此,要么将子元素
更改为集合[组件]
,要么将函数参数祖先
和当前
声明为架构元素
更新3
Person
的一种新成员方法,用于查找后代图中属于循环一部分的所有人:
def descendantsWithCycle = {
def findCycle(current: Person, checked: Set[Person]): Set[Person] =
if (checked contains current) Set(current)
else {
val newChecked = checked + current
current.sons.flatMap(p => findCycle(p, newChecked))
}
findCycle(this, Set())
}
以下方法生成当前人员的所有后代,但不会在循环中丢失:
def descendants(stop: Set[Person] = Set()): Set[Person] =
if(stop contains this) Set()
else this.sons.flatMap(descendants(_,stop + this)) + this
你可以用它来检查你的状况。为了检测任意循环,一旦进入if
的第一个分支,就会得到一个肯定的结果
另一种方法是在构造函数/设置器中强制使图形是非循环的。这允许您在不使用停止集的情况下使用搜索,因为所有现有实例都保证是无循环的,并且可以使用更简单、更快的方法来测试条件。只需一点注意:您有field
son
,有点让人困惑的是,son是一组人。可能是sons
或childrens
?基本上,您定义了一个有向图,希望确保它不包含循环?这是一个算法问题,很容易解决。只需进行BFS搜索,并对allready访问的节点(人员)进行“着色”。如果你到达一个“有色”节点(人),你就有了一个循环。。。意思是人的是他/她自己的后代…@om-nom-nom,注意children已经是复数:-)@om-nom-nom+1,但是children
在没有s的情况下足够复数。请少一点var
s,多一点val
s!非常感谢你。我需要时间来研究这个解决方案。如果图形包含OP想要测试的循环,我将联系shortlyStack overflow。@ziggystar您对解决方案有何建议?您好,非常感谢您的帮助。现在我想在我的实际项目中尝试您的解决方案,只是我发现了一个类型不匹配。我写了有问题的问题。域名没有错,我只是检查了一下。我正在研究一个图形化的UML。我无法更改域。我甚至不能将函数参数祖先和当前声明为ArchitecturalElement,因为ArchitecturalElement没有子元素。现在我看看是否能找到解决办法-(