Scala 在遍历二叉树时构建不可变集合
我正在使用下面的类Scala 在遍历二叉树时构建不可变集合,scala,Scala,我正在使用下面的类MessageTree,来表示包含Message实例的二叉树,我想实现一个方法filter,该方法返回一个新的MessageTree,其中包含满足给定谓词的所有消息。我有一个使用ListBuffer的解决方案,我正在寻找一个在遍历树时构建不可变集合而不是ListBuffer的解决方案。任何见解都将不胜感激 object scratchpad extends App { import scala.collection.mutable.ListBuffer // A c
MessageTree
,来表示包含Message
实例的二叉树,我想实现一个方法filter
,该方法返回一个新的MessageTree,其中包含满足给定谓词的所有消息。我有一个使用ListBuffer的解决方案,我正在寻找一个在遍历树时构建不可变集合而不是ListBuffer的解决方案。任何见解都将不胜感激
object scratchpad extends App {
import scala.collection.mutable.ListBuffer
// A class to represent messages
class Message(val text: String, val user: String, val comments: Int) {
override def toString: String =
"User: " + user + "\n" +
"Text: " + text + " [" + comments + " comments]"
}
/* --------------------------------------------------------------------- */
abstract class MessageTree {
type MessagePredicate = Message => Boolean
def traverse(p: MessagePredicate, storage: ListBuffer[Message]) : Unit
def filter(p: Message => Boolean): MessageTree = filterAcc(p, new Empty)
def filterAcc(p: Message => Boolean, acc: MessageTree): MessageTree
def incl(tweet: Message): MessageTree
def foreach(f: Message => Unit): Unit
}
/* --------------------------------------------------------------------- */
class Empty extends MessageTree {
override def traverse(p: MessagePredicate, storage: ListBuffer[Message]): Unit = {}
override def filterAcc(p: (Message) => Boolean, acc: MessageTree): MessageTree = acc
def incl(tweet: Message): MessageTree = new NonEmpty(tweet, new Empty, new Empty)
def foreach(f: Message => Unit): Unit = ()
}
/* --------------------------------------------------------------------- */
class NonEmpty(elem: Message, left: MessageTree, right: MessageTree) extends MessageTree {
override def traverse(p: MessagePredicate, storage: ListBuffer[Message]): Unit = {
left.traverse(p, storage)
if (p(elem)) storage += elem
right.traverse(p, storage)
}
override def filterAcc(p: (Message) => Boolean, acc: MessageTree): MessageTree = {
val tweet_collector = ListBuffer.empty[Message]
traverse(p, tweet_collector)
def loop(listBuffer: ListBuffer[Message], accum: MessageTree) : MessageTree = {
if (listBuffer.isEmpty) accum
else loop(listBuffer.tail, accum incl listBuffer.head)
}
loop(tweet_collector, acc)
}
def incl(x: Message): MessageTree = {
if (x.text < elem.text) new NonEmpty(elem, left.incl(x), right)
else if (elem.text < x.text) new NonEmpty(elem, left, right.incl(x))
else this
}
def foreach(f: Message => Unit): Unit = {
left.foreach(f)
f(elem)
right.foreach(f)
}
}
/* --------------------------------------------------------------------- */
/* Test
/* --------------------------------------------------------------------- */
val keyword_list: List[String] = "one" :: "three" :: "five" :: "seven" :: "nine" :: Nil
def search_predicate(msg: Message): Boolean = {
keyword_list.exists(msg.text.contains(_))
}
val msg_00 = new Message("zero", "John_00", 50)
val msg_01 = new Message("one", "John_01", 10)
val msg_02 = new Message("two", "John_02", 20)
val msg_03 = new Message("three", "John_03", 30)
val msg_04 = new Message("four", "John_04", 40)
val msg_05 = new Message("five", "John_05", 50)
val tmp_message_tree = new NonEmpty(msg_00, new Empty, new Empty)
val message_tree = tmp_message_tree incl msg_01 incl msg_02 incl msg_03 incl msg_04 incl msg_05
println("All messages")
message_tree foreach println
println("Filtered messages")
(message_tree filter search_predicate) foreach println
}
对象草稿行扩展应用程序{
导入scala.collection.mutable.ListBuffer
//表示消息的类
类消息(val文本:String,val用户:String,val注释:Int){
重写def toString:字符串=
用户:“+User+”\n+
“文本:“+Text+”[“+comments+”comments]”
}
/* --------------------------------------------------------------------- */
抽象类消息树{
类型MessagePredicate=Message=>Boolean
def遍历(p:MessagePredicate,存储:ListBuffer[Message]):单位
def过滤器(p:Message=>Boolean):MessageTree=filterAcc(p,新为空)
def filterAcc(p:Message=>Boolean,acc:MessageTree):MessageTree
def incl(tweet:Message):MessageTree
def foreach(f:Message=>Unit):单位
}
/* --------------------------------------------------------------------- */
类Empty扩展了MessageTree{
覆盖def遍历(p:MessagePredicate,storage:ListBuffer[Message]):Unit={}
覆盖def过滤器acc(p:(消息)=>布尔值,acc:MessageTree:MessageTree=acc
def incl(tweet:Message):MessageTree=new非空(tweet,new Empty,new Empty)
def foreach(f:Message=>Unit):Unit=()
}
/* --------------------------------------------------------------------- */
类NonEmpty(elem:Message,left:MessageTree,right:MessageTree)扩展了MessageTree{
覆盖def遍历(p:MessagePredicate,存储:ListBuffer[Message]):单位={
左。遍历(p,存储)
if(p(elem))存储+=elem
右。遍历(p,存储)
}
覆盖def filterAcc(p:(消息)=>布尔值,acc:MessageTree:MessageTree={
val tweet_collector=ListBuffer.empty[消息]
遍历(p、tweet_收集器)
def循环(listBuffer:listBuffer[Message],accum:MessageTree):MessageTree={
if(listBuffer.isEmpty)累计
else循环(listBuffer.tail、accum包括listBuffer.head)
}
环路(tweet_收集器,acc)
}
def incl(x:消息):消息树={
if(x.textUnit):单位={
左。foreach(f)
f(要素)
对。foreach(f)
}
}
/* --------------------------------------------------------------------- */
/*试验
/* --------------------------------------------------------------------- */
val关键字_list:list[String]=“一”:“三”:“五”:“七”:“九”::零
def search_谓词(msg:Message):布尔={
关键字\u list.exists(msg.text.contains(\u))
}
val msg_00=新消息(“零”,“约翰_00”,50)
val msg_01=新消息(“一”,“约翰_01”,10)
val msg_02=新消息(“两个”,“约翰_02”,20)
val msg_03=新消息(“三”,“约翰_03”,30)
val msg_04=新消息(“四”,“约翰_04”,40)
val msg_05=新消息(“五”,“约翰_05”,50)
val tmp_message_tree=new NonEmpty(msg_00,new Empty,new Empty)
val消息树=tmp消息树包括消息树01包括消息树02包括消息树03包括消息树04包括消息树05
println(“所有消息”)
每个println的消息树
println(“过滤消息”)
(消息树筛选器搜索谓词)foreach println
}
输出是
所有消息
用户:John_05正文:五条[50条评论]
用户:John_04
正文:四条[40条评论]
用户:John_01
正文:一[10条评论]
用户:John_03
正文:三条[30条评论]
用户:John_02
正文:两条[20条评论]
用户:John_00
文本:零[50条评论] 过滤消息 用户:John_05
正文:五条[50条评论]
用户:John_01
正文:一[10条评论]
用户:John_03
正文:三[30条评论]
就快到了:只需按如下方式更改导线:
def traverse(p: MessagePredicate):List[Message] = {
left.traverse(p) ++
(if (p(elem)) List(elem) else List()) ++
right.traverse(p)
}
这个解决方案很简单,但是它使用了太多的列表浓缩,这很昂贵。另一种方法是使用蓄能器降低浓度:
def traverse(p: MessagePredicate, acc:List[Message]):List[Message] = {
val r = right.traverse(acc)
left.traverse(p, if(p (elem)) elem::r else r)
}
对于空节点:
def traverse(p: MessagePredicate, acc:List[Message]):List[Message] = acc
太好了,谢谢!是否有一种(半)系统的方式来达成解决方案,或者让您看到解决方案的主要是经验?主要是经验:)