我正在尝试解决coursera scala课程的第三个任务。我已经完成了其中一些,但是在处理某个特定函数时,我认为我没有抓住重点。我必须实现filter函数,该函数将返回给定谓词满足的所有推文集合中的子集。我已经实现了一些函数,我认为这些函数将有助于我完成任务,但是测试失败。
请注意,请不要给我烤好的代码,因为这将违反coursera的荣誉准则。我只想要一些能帮助我调试逻辑并帮助我看到我哪里出错以及为什么测试失败的东西。
我认为这个问题主要在于filterAcc函数,当没有任何情况适用时,它返回"empty",但我不确定我能做什么来解决这个问题。这就是一切失败的地方吗?如果是,我该怎么解决?
更新: 我也曾试图通过以下方式解决这个问题:
这种方法现在确保了如果没有匹配的条件,则仍会进行递归调用,但同时累加器不会增加。测试仍然失败。我的逻辑错误在哪里?
感谢@lpiepiora和@Ende Neu的努力告诉我,acc的起始应该为空。我最终使用了联合,因为我的想法太固化了,我就是摆脱不了这个思路。下面是最终的代码:
请注意,请不要给我烤好的代码,因为这将违反coursera的荣誉准则。我只想要一些能帮助我调试逻辑并帮助我看到我哪里出错以及为什么测试失败的东西。
abstract class TweetSet {
def isEmpty: Boolean
/**
* This method takes a predicate and returns a subset of all the elements
* in the original set for which the predicate is true.
*
* Question: Can we implment this method here, or should it remain abstract
* and be implemented in the subclasses?
*/
def filter(p: Tweet => Boolean): TweetSet
/**
* This is a helper method for `filter` that propagetes the accumulated tweets.
*/
def filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet
/**
* Returns a new `TweetSet` that is the union of `TweetSet`s `this` and `that`.
*
* Question: Should we implment this method here, or should it remain abstract
* and be implemented in the subclasses?
*/
def union(that: TweetSet): TweetSet;
/**
* Returns the tweet from this set which has the greatest retweet count.
*
* Calling `mostRetweeted` on an empty set should throw an exception of
* type `java.util.NoSuchElementException`.
*
* Question: Should we implment this method here, or should it remain abstract
* and be implemented in the subclasses?
*/
def mostRetweeted: Tweet = ???
/**
* Returns a list containing all tweets of this set, sorted by retweet count
* in descending order. In other words, the head of the resulting list should
* have the highest retweet count.
*
* Hint: the method `remove` on TweetSet will be very useful.
* Question: Should we implment this method here, or should it remain abstract
* and be implemented in the subclasses?
*/
def descendingByRetweet: TweetList = ???
/**
* The following methods are already implemented
*/
/**
* Returns a new `TweetSet` which contains all elements of this set, and the
* the new element `tweet` in case it does not already exist in this set.
*
* If `this.contains(tweet)`, the current set is returned.
*/
def incl(tweet: Tweet): TweetSet
/**
* Returns a new `TweetSet` which excludes `tweet`.
*/
def remove(tweet: Tweet): TweetSet
/**
* Tests if `tweet` exists in this `TweetSet`.
*/
def contains(tweet: Tweet): Boolean
/**
* This method takes a function and applies it to every element in the set.
*/
def foreach(f: Tweet => Unit): Unit
}
class Empty extends TweetSet {
def union(that: TweetSet): TweetSet = that
def isEmpty = true
def filter(p: Tweet=> Boolean): TweetSet = new Empty()
def filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet = new Empty()
/**
* The following methods are already implemented
*/
def contains(tweet: Tweet): Boolean = false
def incl(tweet: Tweet): TweetSet = new NonEmpty(tweet, new Empty, new Empty)
def remove(tweet: Tweet): TweetSet = this
def foreach(f: Tweet => Unit): Unit = ()
}
class NonEmpty(elem: Tweet, left: TweetSet, right: TweetSet) extends TweetSet {
def union(that: TweetSet): TweetSet = (left.union(right)).union(that).incl(elem)
val isEmpty = false
def filter(p: Tweet => Boolean): TweetSet = filterAcc(p,left.union(right))
def filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet = {
if(acc.isEmpty) acc
else if(p(elem)) {acc.incl(elem); left.filterAcc(p,acc).union(right.filterAcc(p,acc))}
else new Empty
}
/**
* The following methods are already implemented
*/
def contains(x: Tweet): Boolean =
if (x.text < elem.text) left.contains(x)
else if (elem.text < x.text) right.contains(x)
else true
def incl(x: Tweet): TweetSet = {
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 remove(tw: Tweet): TweetSet =
if (tw.text < elem.text) new NonEmpty(elem, left.remove(tw), right)
else if (elem.text < tw.text) new NonEmpty(elem, left, right.remove(tw))
else left.union(right)
def foreach(f: Tweet => Unit): Unit = {
f(elem)
left.foreach(f)
right.foreach(f)
}
}
我认为这个问题主要在于filterAcc函数,当没有任何情况适用时,它返回"empty",但我不确定我能做什么来解决这个问题。这就是一切失败的地方吗?如果是,我该怎么解决?
更新: 我也曾试图通过以下方式解决这个问题:
def filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet = {
if(acc.isEmpty) acc
else if(p(elem)) {acc.incl(elem); left.filterAcc(p,acc).union(right.filterAcc(p,acc))}
else left.filterAcc(p,acc).union(right.filterAcc(p,acc))
}
这种方法现在确保了如果没有匹配的条件,则仍会进行递归调用,但同时累加器不会增加。测试仍然失败。我的逻辑错误在哪里?
感谢@lpiepiora和@Ende Neu的努力告诉我,acc的起始应该为空。我最终使用了联合,因为我的想法太固化了,我就是摆脱不了这个思路。下面是最终的代码:
def filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet = {
if(left.isEmpty && right.isEmpty) acc
else if(p(elem)){ left.filterAcc(p,acc.incl(elem)).union(right.filterAcc(p,acc.incl(elem)))}
else left.filterAcc(p,acc).union(right.filterAcc(p,acc))
}
TweetSet
是不可变的,所以如果你调用一个添加元素的方法,你会得到一个新的集合。你必须对结果做些什么,否则它就会丢失。在编写filterAcc
时不需要使用union
- 使用acc
累加器和递归即可。此外,当你第一次运行该方法时会发生什么?acc
的值是什么 - 它有任何元素吗?另外,如果你遇到空集,会发生什么 - 返回什么? - lpiepioraEmptySet
并且使用filterAcc(_ => true, acc)
,其中acc
已经包含了一些元素,你会返回什么?你确定EmptySet
是正确的吗? - lpiepiora