Skip to content

Commit

Permalink
Implement 3rd assignment
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-myltsev committed Dec 12, 2013
1 parent 1c8e9e7 commit 1987a82
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 25 deletions.
24 changes: 12 additions & 12 deletions a3-objsets/src/main/scala/objsets/TweetReader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ object TweetReader {

object ParseTweets {
import scala.util.parsing.json._

def getList[T](s: String): List[T] =
JSON.parseFull(s).get.asInstanceOf[List[T]]

Expand Down Expand Up @@ -37,36 +37,36 @@ object TweetReader {
val buf = new StringBuffer
for (tw <- tws) {
val json = "{ \"user\": \"" + tw.user + "\", \"text\": \"" +
tw.text.replaceAll(""""""", "\\\\\\\"") + "\", \"retweets\": " +
tw.retweets + ".0 }"
tw.text.replaceAll(""""""", "\\\\\\\"") + "\", \"retweets\": " +
tw.retweets + ".0 }"
buf.append(json + ",\n")
}
buf.toString
}

val sites = List("gizmodo", "TechCrunch", "engadget", "amazondeals", "CNET", "gadgetlab", "mashable")

private val gizmodoTweets = TweetReader.ParseTweets.getTweetData("gizmodo", TweetData.gizmodo)
private val techCrunchTweets = TweetReader.ParseTweets.getTweetData("TechCrunch", TweetData.TechCrunch)
private val engadgetTweets = TweetReader.ParseTweets.getTweetData("engadget", TweetData.engadget)
private val amazondealsTweets = TweetReader.ParseTweets.getTweetData("amazondeals", TweetData.amazondeals)
private val cnetTweets = TweetReader.ParseTweets.getTweetData("CNET", TweetData.CNET)
private val gadgetlabTweets = TweetReader.ParseTweets.getTweetData("gadgetlab", TweetData.gadgetlab)
private val mashableTweets = TweetReader.ParseTweets.getTweetData("mashable", TweetData.mashable)

private val sources = List(gizmodoTweets, techCrunchTweets, engadgetTweets, amazondealsTweets, cnetTweets, gadgetlabTweets, mashableTweets)

val tweetMap: Map[String, List[Tweet]] =
Map() ++ Seq((sites(0) -> gizmodoTweets),
(sites(1) -> techCrunchTweets),
(sites(2) -> engadgetTweets),
(sites(3) -> amazondealsTweets),
(sites(4) -> cnetTweets),
(sites(5) -> gadgetlabTweets),
(sites(6) -> mashableTweets))
(sites(1) -> techCrunchTweets),
(sites(2) -> engadgetTweets),
(sites(3) -> amazondealsTweets),
(sites(4) -> cnetTweets),
(sites(5) -> gadgetlabTweets),
(sites(6) -> mashableTweets))

val tweetSets: List[TweetSet] = sources.map(tweets => toTweetSet(tweets))

private val siteTweetSetMap: Map[String, TweetSet] =
Map() ++ (sites zip tweetSets)

Expand Down
62 changes: 49 additions & 13 deletions a3-objsets/src/main/scala/objsets/TweetSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import TweetReader._
class Tweet(val user: String, val text: String, val retweets: Int) {
override def toString: String =
"User: " + user + "\n" +
"Text: " + text + " [" + retweets + "]"
"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
* subtree are smaller than the tweet at `b`. The elements in the right subtree are
* larger.
*
* Note that the above structure requires us to be able to compare two tweets (we
Expand All @@ -42,7 +42,7 @@ abstract class TweetSet {
* Question: Can we implment this method here, or should it remain abstract
* and be implemented in the subclasses?
*/
def filter(p: Tweet => Boolean): TweetSet = ???
def filter(p: Tweet => Boolean): TweetSet = filterAcc(p, new Empty)

/**
* This is a helper method for `filter` that propagetes the accumulated tweets.
Expand All @@ -55,7 +55,11 @@ abstract class TweetSet {
* Question: Should we implment this method here, or should it remain abstract
* and be implemented in the subclasses?
*/
def union(that: TweetSet): TweetSet = ???
def union(that: TweetSet): TweetSet = filterAcc(tw => true, that)

def isEmpty: Boolean

def size: Int

/**
* Returns the tweet from this set which has the greatest retweet count.
Expand All @@ -66,7 +70,9 @@ abstract class TweetSet {
* Question: Should we implment this method here, or should it remain abstract
* and be implemented in the subclasses?
*/
def mostRetweeted: Tweet = ???
def mostRetweetedHelper(mostTweet: Tweet): Tweet

def mostRetweeted: Tweet

/**
* Returns a list containing all tweets of this set, sorted by retweet count
Expand All @@ -77,8 +83,7 @@ abstract class TweetSet {
* Question: Should we implment this method here, or should it remain abstract
* and be implemented in the subclasses?
*/
def descendingByRetweet: TweetList = ???

def descendingByRetweet: TweetList

/**
* The following methods are already implemented
Expand Down Expand Up @@ -110,8 +115,17 @@ abstract class TweetSet {

class Empty extends TweetSet {

def filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet = ???
def filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet = acc

def isEmpty: Boolean = true

def mostRetweetedHelper(mostTweet: Tweet): Tweet = mostTweet

def mostRetweeted: Tweet = throw new java.util.NoSuchElementException

def descendingByRetweet: TweetList = Nil

def size: Int = 0

/**
* The following methods are already implemented
Expand All @@ -128,8 +142,30 @@ class Empty extends TweetSet {

class NonEmpty(elem: Tweet, left: TweetSet, right: TweetSet) extends TweetSet {

def filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet = ???
def filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet = {
val newAcc = if (p(elem)) acc incl elem else acc
val newLeft = left filterAcc (p, newAcc)
right filterAcc (p, newLeft)
}

def isEmpty: Boolean = false

def size: Int = 1 + left.size + right.size

def mostRetweetedHelper(mostTweet: Tweet): Tweet = {
val mostTweetLeft = left.mostRetweetedHelper(mostTweet)
val mostTweetRight = right.mostRetweetedHelper(mostTweet)

val t1 = if (mostTweetRight.retweets > mostTweetLeft.retweets) mostTweetRight else mostTweetLeft
if (t1.retweets > elem.retweets) t1 else elem
}

def mostRetweeted: Tweet = mostRetweetedHelper(elem)

def descendingByRetweet: TweetList = {
val mostTweet = mostRetweeted
new Cons(mostTweet, remove(mostTweet).descendingByRetweet)
}

/**
* The following methods are already implemented
Expand Down Expand Up @@ -179,19 +215,19 @@ 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")

lazy val googleTweets: TweetSet = ???
lazy val appleTweets: TweetSet = ???
private def tweetsByWords(words: List[String]) = TweetReader.allTweets.filter(x => words.exists(x.text.contains(_)))
lazy val googleTweets: TweetSet = tweetsByWords(google)
lazy val appleTweets: TweetSet = tweetsByWords(apple)

/**
* A list of all tweets mentioning a keyword from either apple or google,
* sorted by the number of retweets.
*/
lazy val trending: TweetList = ???
lazy val trending: TweetList = (googleTweets union appleTweets).descendingByRetweet
}

object Main extends App {
Expand Down
27 changes: 27 additions & 0 deletions a3-objsets/src/test/scala/objsets/TweetSetSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,38 @@ class TweetSetSuite extends FunSuite {
}
}

test("union of two parts of set - odd/even retweets") {
val oddTweets = TweetReader.allTweets filter (x => x.retweets % 2 == 1)
val evenTweets = TweetReader.allTweets filter (x => x.retweets % 2 == 0)
assert(TweetReader.allTweets.size == oddTweets.size + evenTweets.size)
}

test("union of two parts of set - odd/even text size") {
val oddTweets = TweetReader.allTweets filter (x => x.text.length % 2 == 1)
val evenTweets = TweetReader.allTweets filter (x => x.text.length % 2 == 0)
assert(TweetReader.allTweets.size == oddTweets.size + evenTweets.size)
}

test("mostRetweets") {
val mostTweet = TweetReader.allTweets.mostRetweeted
assert(TweetReader.allTweets.filter(p => p.retweets > mostTweet.retweets).isEmpty)
}

test("descending: set5") {
new TestSets {
val trends = set5.descendingByRetweet
assert(!trends.isEmpty)
assert(trends.head.user == "a" || trends.head.user == "b")
}
}

test("descending") {
def isSorted(head: Tweet, tail: TweetList): Boolean = {
if (tail.isEmpty) true
else if (head.retweets >= tail.head.retweets) isSorted(tail.head, tail.tail)
else false
}
val descTweets = TweetReader.allTweets.descendingByRetweet
assert(isSorted(descTweets.head, descTweets.tail))
}
}

0 comments on commit 1987a82

Please sign in to comment.