第三次作业
https://class.coursera.org/progfun-003/assignment/view?assignment_id=9
这次作业,是我第一次没能够完全独立完成,还是参照了网上一些学习者的评论等之后才做出来的
虽然他们没有直接给出答案,甚至有些思路都是错的,但毕竟还不算是独立完成
对于函数式编程,对于递归,对于算法这个软肋,革命尚未成功,同志仍需努力!
class Tweet(val user : String, val text: String, val retweets : Int) {} abstract class TweetSet { /** * 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 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 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) } }
/** This method takes a predicate and returns a subset of all the elements * in the original set for which the predicate is true. */ def filter(p: Tweet => Boolean): TweetSet def filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet
基类中: def filter(p: Tweet => Boolean): TweetSet = { filterAcc(p, new Empty) } def filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet 子类中: // NonEmpty def filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet = { val accResult1 = left.filterAcc(p, acc) val accResult2 = right.filterAcc(p, accResult1) if (p(elem)) accResult2.incl(elem) else accResult2 } // Empty def unionAcc(acc: TweetSet): TweetSet = acc
def union(that: TweetSet): TweetSet 我本来以为很简单,随手写: // NonEmpty def union(that: TweetSet): TweetSet = { that.union(left).union(right).incl(elem) } // Empty def union(that: TweetSet): TweetSet = that
// 基类 def union(that: TweetSet): TweetSet = { unionAcc(that) } // 暂不实现 def unionAcc(that: TweetSet): TweetSet // Empty def unionAcc(acc: TweetSet): TweetSet = acc // NonEmpty def unionAcc(acc: TweetSet): TweetSet = { left.unionAcc(right.unionAcc(acc)).incl(elem) }
// List定义 class Cons(val head : Tweet, val tail: TweetList) extends TweetList { def isEmpty = false } def compareSet(t1: Tweet, s: TweetSet): Tweet = { /** * It's Error that: * * if (t1. retweets >= v.retweets) t1 * else s.mostRetweeted.retweets */ val v = s.mostRetweeted if (t1. retweets >= v. retweets) t1 else v } def mostRetweeted: Tweet = { if (left.isEmpty && right.isEmpty) elem else if (left.isEmpty) compareSet(elem, right) else if (right.isEmpty) compareSet(elem, left) else compareSet(compareSet(elem, left), right) } def descendingByRetweet: TweetList = { new Cons(mostRetweeted, this.remove(mostRetweeted).descendingByRetweet) }
object GoogleVsApple { val google = List( "android", "Android" , "galaxy" , "Galaxy" , "nexus" , "Nexus" ) val apple = List( "ios", "iOS" , "iphone" , "iPhone" , "ipad" , "iPad" ) lazy val googleTweets : TweetSet = allTweets.filter(???) lazy val appleTweets : TweetSet = allTweets.filter(???) }
def func(s:String /* Tweet内容 */):Booean{ { 对于每一个google里的String str if(s.contains(str)){ return true } } return false } lazy val googleTweets : TweetSet = allTweets.filter(x=>func(x.text))
lazy val googleTweets : TweetSet = allTweets.filter(x => google.exists(s => x.text.contains(s)))
package objsets import common._ import TweetReader._ /** * A class to represent tweets. */ class Tweet(val user : String, val text: String, val retweets : Int) { override def toString: String = "User: " + user + "\n" + "Text: " + text + " [" + retweets + "]" } /** * This represents a set of objects of type ` Tweet` in the form of a binary search * tree. Every branch in the tree has two children (two `TweetSet`s). There is an * invariant which always holds: for every branch `b`, all elements in the left * subtree are smaller than the tweet at `b`. The eleemnts in the right subtree are * larger. * * Note that the above structure requires us to be able to compare two tweets (we * need to be able to say which of two tweets is larger, or if they are equal). In * this implementation, the equality / order of tweets is based on the tweet's text * (see `def incl`). Hence, a `TweetSet` could not contain two tweets with the same * text from different users. * * * The advantage of representing sets as binary search trees is that the elements * of the set can be found quickly. If you want to learn more you can take a look * at the Wikipedia page [1], but this is not necessary in order to solve this * assignment. * * [1] http://en.wikipedia.org/wiki/Binary_search_tree */ abstract class TweetSet { /** * 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 = { filterAcc(p, new Empty) } /** * 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? */ /** * At first I implement it by that.union(left).union(right). incl(elem ) * However it's error and will cause infinite loop */ def union(that: TweetSet): TweetSet = { unionAcc(that) } def unionAcc(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 def isEmpty: Boolean /** * 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 filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet = acc def unionAcc(acc: TweetSet): TweetSet = acc def mostRetweeted: Tweet = throw new java.util.NoSuchElementException def isEmpty: Boolean = { true } def descendingByRetweet: TweetList = Nil /** * 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 filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet = { val accResult1 = left.filterAcc(p, acc) val accResult2 = right.filterAcc(p, accResult1) if (p(elem)) accResult2.incl(elem) else accResult2 } def unionAcc(acc: TweetSet): TweetSet = { left.unionAcc(right.unionAcc(acc)).incl(elem) } def isEmpty: Boolean = false // Take me a long long time to complete def compareSet(t1: Tweet, s: TweetSet): Tweet = { val v = s.mostRetweeted if (t1. retweets >= v. retweets) t1 else v /** * It's Error that: * * if (t1. retweets >= v.retweets) t1 * else s.mostRetweeted.retweets */ } def mostRetweeted: Tweet = { if (left.isEmpty && right.isEmpty) elem else if (left.isEmpty) compareSet(elem, right) else if (right.isEmpty) compareSet(elem, left) else compareSet(compareSet(elem, left), right) } def descendingByRetweet: TweetList = { new Cons(mostRetweeted, this.remove(mostRetweeted).descendingByRetweet) } /** * 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) } } trait TweetList { def head: Tweet def tail: TweetList def isEmpty: Boolean def foreach(f: Tweet => Unit): Unit = if (!isEmpty) { f(head) tail.foreach(f) } } object Nil extends TweetList { def head = throw new java.util.NoSuchElementException("head of EmptyList") def tail = throw new java.util.NoSuchElementException("tail of EmptyList") def isEmpty = true } class Cons(val head : Tweet, val tail: TweetList) extends TweetList { def isEmpty = false } object GoogleVsApple { val google = List( "android", "Android" , "galaxy" , "Galaxy" , "nexus" , "Nexus" ) val apple = List( "ios", "iOS" , "iphone" , "iPhone" , "ipad" , "iPad" ) /** * Take me a long time to complete * As someone said: * That hint is one of the best hints in this assignment. */ lazy val googleTweets : TweetSet = allTweets.filter(x => google.exists(s => x.text.contains(s))) lazy val appleTweets : TweetSet = allTweets.filter(x => apple.exists(s => x.text.contains(s))) /** * A list of all tweets mentioning a keyword from either apple or google, * sorted by the number of retweets. */ lazy val trending : TweetList = googleTweets.union(appleTweets ).descendingByRetweet } object Main extends App { // Print the trending tweets GoogleVsApple.trending foreach println }