Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions scala-thoughts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
First, a rant:

I must say, I found learning Scala incredibly frustrating! I think the biggest
frustration I had was with the documentation. While Prof. Ben provided us useful
resources in the repository's README and relevant resources for some of the
problems, it was not easy to figure out the canonical resource for documentation.
I found that the official documentation site was not easy to navigate and kind
of all over the place. What would probably have been beneficial is something
like the [Go tour](https://tour.golang.org/welcome/1). There are many
idiosyncrasies not seen in other languages, and a thorough tour would have been
helpful; however, we have a pretty significant time constraint, so it's possible
I was not spending enough time looking through docs.

Most of this frustration stemmed from the lack of example code. I think one or
two good examples are worth more than hundreds of words of documentation,
and I couldn't find these as easily for Scala, both on official resources and
on Stack Overflow.

Now, more rational analysis:

I think the Scala authors did a great job of providing "map"-like functions to
be able to apply actions on every element in a list. Aside from `map`, which is
common in most languages, I enjoyed using `foldLeft` and `filter`. These are
simple operations and it's nice that they were simplified to single, built-in
functions.

Also, I found options to be an interesting concept. Instead of just having `null`
values, I thought it clever and could imagine some use cases to have
optional values. I've run into annoying bugs and errors just because I haven't
explicitly dealt with null values in my code, so it's nice to be forced to handle
the cases when appropriate, and it isn't overly burdensome.

At the moment, I dislike Collections. At least for our problem set, I found that
I would have been fine using just Lists and Maps, but I ran into Sequences and
ListBuffers, and seen several other things related to Collections in the docs.
I know having data structures for many different cases are useful, so I don't
doubt that this could be useful, but I was annoyed at how much conversion
between data structures there was in such a simple assignment. I also got stuck
for quite long on how to properly append an item to a List for the
sumOfTwo problem. I had been using List.concat previously, but then found that
I had trouble simply appending an item to an existing list. This is a case where
examples in docs would've helped.

That being said, I would love to learn more about working with data structures:
how to properly iterate over them (something I found oddly unintuitive),
understanding the best use cases for each, and how to manipulate them for each
case.

2 changes: 1 addition & 1 deletion src/main/scala/exercises/00_HelloWorld.scala
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,5 @@ object HelloWorld {
* This exercise is taken from ScalaLabs:
* https://github.com/scala-labs/scala-labs/blob/master/labs/src/main/scala/org/scalalabs/basic/lab01/HelloWorldExercise.scala
*/
val message: String = "Change me"
val message: String = "Hello world!"
}
2 changes: 1 addition & 1 deletion src/main/scala/exercises/01_Echo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ object Echo {
* This exercise is taken from ScalaLabs:
* https://github.com/scala-labs/scala-labs/blob/master/labs/src/main/scala/org/scalalabs/basic/lab01/HelloWorldExercise.scala
*/
def echo(message: String): String = "Change me"
def echo(message: String): String = message
}
9 changes: 8 additions & 1 deletion src/main/scala/exercises/02_Fibonacci.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ object Fibonacci {
* fib(2) = 1
* fib(n) = fib(n-1) + fib(n-2)
*/
def fib(n: Int): Int = 0


def fib(n: Int): Int = {
if (n == 1) return 1
if (n == 2) return 1

var toReturn: Int = fib(n-1) + fib(n-2)
toReturn
}
}
5 changes: 4 additions & 1 deletion src/main/scala/exercises/03_Exponent.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ object Exponent {
* NOTE: Scala has a built-in exponent function, but you're not allowed to
* use it to implement `expt`
*/
def expt(n: Int, e: Int): Int = -1
def expt(n: Int, e: Int): Int = {
if (e == 0) 1
n * expt(n, e-1)
}

}
22 changes: 20 additions & 2 deletions src/main/scala/exercises/04_Options.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,15 @@ object Options {
* - does not exist: "not existing"
*/
def roomState(rooms: Map[Int, Option[String]], room: Int): String = {
error("Fix me")
val status: Option[Option[String]] = rooms.get(room)
if (status != None) {
if (status == Some(Some("locked"))) return "not available"
if (status == Some(None)) return "empty"
else return rooms.get(room).get.get
} else {
"not existing"
}

}

/**
Expand All @@ -44,6 +52,16 @@ object Options {
* to convert a possible numeric String (e.g. Some("12")) to an integer
*/
def totalPeopleInRooms(rooms: Map[Int, Option[String]]): Int = {
error("Fix me")
var total = 0
rooms foreach(x => total += optionStringToInt(x._2))
return total
}

def optionStringToInt(option: Option[String]): Int = {
try {
option.get.toInt
} catch{
case e: Exception => 0
}
}
}
34 changes: 29 additions & 5 deletions src/main/scala/exercises/05_Patterns.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,15 @@ object PatternMatching {
* For expected solution see @PatternMatchingTest
*************************************************************************/

def describeLanguage(s: String): String = {
error("fix me")
def describeLanguage(s: String): String = s match {
case "Java" => "OOP"
case "Smalltalk" => "OOP"
case "Clojure" => "Functional"
case "Haskell" => "Functional"
case "Scala" => "Hybrid"
case "C" => "Procedural"
case "Oz" => "Unknown"
// error("fix me")
}

/**
Expand All @@ -55,16 +62,33 @@ object PatternMatching {
*
* - anything else, the function result is "Some Scala class"
*/
def matchOnInputType(in: Any): String = {
error("fix me")
def matchOnInputType(in: Any): String = in match {
case y: String => "A string with length ".concat(y.length().toString())
case y: Int => "A positive integer"
case y: Person => "A person with name: ".concat(y.name)
case y: Range if (y.toList.length > 10) => "Seq with more than 10 elements"
case y: Seq[Any] if (y.length >= 3) => s"first: ${y(0)}, second: ${y(1)}, rest: ${y drop 2}"
case null => "A null value"
case _ => "Some Scala class"
}

def greaterThanThree(in: List[Any]): String = {
val first = in(0)
val second = in(1)
val tail = in.slice(2, in.size)

return s"first: $first, second: $second, rest: $tail"
}

/**
* If the person is older than 30, return an `Option` with the person's name;
* otherwise return `None`
*/
def older(p: Person): Option[String] = {
error("fix me")
val name: Option[String] = Some(p.name)
if (p.age > 30) name
else None
// error("fix me")
}
}

Expand Down
71 changes: 35 additions & 36 deletions src/main/scala/exercises/06_Collections.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@ object Collections {
*
*/
def firstElementInList[T](l: List[T]): T = {
error("fix me")
l.head
}

/**
* Get the sum of all the elements in the list, e.g. sumOfList(List(1,2,3)) = 6.
*/
def sumOfList(l: List[Int]): Int = {
error("fix me")
l.foldLeft(0)((first, second) => first + second)
}

/**
Expand All @@ -51,7 +51,7 @@ object Collections {
* - ... etc
*/
def lastElementInList[T](l: List[T]): T = {
error("fix me")
l.last
}

/**
Expand All @@ -65,7 +65,7 @@ object Collections {
* - ... etc
*/
def nthElementInList[T](n: Int, l: List[T]): T = {
error("fix me")
l(n)
}

/**
Expand All @@ -79,7 +79,9 @@ object Collections {
* - ... etc
*/
def concatLists[T](l1: List[T], l2: List[T]): List[T] = {
error("fix me")
val l3: List[T] = List.concat(l1, l2)
l3

}

/**
Expand All @@ -92,7 +94,7 @@ object Collections {
*
*/
def sortList[T <% Ordered[T]](list: List[T]): List[T] = {
error("fix me")
list.sorted
}

/**
Expand All @@ -103,7 +105,7 @@ object Collections {
* to implement in your own free-style way.
*/
def elementExists[T](l: List[T], e: T): Boolean = {
error("fix me")
l.contains(e)
}

/**
Expand All @@ -114,7 +116,7 @@ object Collections {
* pattern match or some other method.
*/
def oddElements(iList: List[Int]): List[Int] = {
error("fix me")
iList.filter(i => i % 2 != 0)
}

/**
Expand All @@ -130,7 +132,8 @@ object Collections {
* neat way using recursion.
*/
def tails[T](l: List[T]): List[List[T]] = {
error("fix me")
if (l.length == 0) List(l)
else List.concat(List(l), tails(l.drop(1)))
}

/**
Expand All @@ -139,23 +142,40 @@ object Collections {
* As usual, various ways exist: pattern matching, folding, ...
*/
def maxElementInList(l: List[Int]): Int = {
error("fix me")
var max = -99999999
l.foreach{ x =>
if (x > max) {
max = x
}
}
max
}

/**
* Calculate the sum of the equally position elements
* of the two list
*/
def sumOfTwo(l1: List[Int], l2: List[Int]): List[Int] = {
error("fix me")
var l3: List[Int]= List()
if (l1.length == 0 && l2.length != 0) {
l2
} else if (l1.length != 0 && l2.length == 0) {
l1
} else {
for(n <- 0 until l1.length) {
val item: Int = l1(n) + l2(n)
l3 = l3 ::: List(item)
}
l3
}
}

/**
* For this exercise preferably make use of the sumOfTwo
* method above
*/
def sumOfMany(l: List[Int]*): List[Int] = {
error("fix me")
l.foldLeft(List(0, 0, 0))((first, second) => sumOfTwo(first, second))
}

case class Person(age: Int, firstName: String, lastName: String)
Expand All @@ -165,30 +185,9 @@ object Collections {
* The idea is to rewrite the method into more functional style.
*/
def separateTheYoungFromTheOld(persons: List[Person]): List[List[String]] = {
var youngins: ListBuffer[Person] = new ListBuffer[Person]()
var elders: ListBuffer[Person] = new ListBuffer[Person]()
var validYoungNames: ListBuffer[String] = new ListBuffer[String]()
var validOldNames: ListBuffer[String] = new ListBuffer[String]()

for (person <- persons) {
if (person.age < 18) {
youngins += person
} else {
elders += person
}
}

var sortedYoung = youngins.toList.sortBy(_.age)
var sortedOld = elders.toList.sortBy(_.age)

for (young <- sortedYoung) {
validYoungNames += young.firstName
}
for (old <- sortedOld) {
validOldNames += old.firstName
}

List(validYoungNames.toList, validOldNames.toList)
val youngins = persons.filter(_.age < 18).sortBy(_.age)
val elders = persons.filter(_.age >= 18).sortBy(_.age)
List(youngins.map(human => human.firstName), elders.map(human => human.firstName))
}
}

Expand Down
7 changes: 6 additions & 1 deletion src/main/scala/exercises/07_Palindrome.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ object Palindrome {
* Hint: the Scala collections API is your friend
* http://docs.scala-lang.org/overviews/collections/overview.html
*/
def isPalindrome(s: String): Boolean = throw new NotImplementedError
def isPalindrome(s: String): Boolean = {
val removed: String = s.filter(_.isLetter).toLowerCase()
val reversed: String = removed.reverse
if (reversed == removed) true
else false
}

}
Binary file added src/main/scala/exercises/exercises/Fibonacci$.class
Binary file not shown.
Binary file not shown.
Binary file added src/main/scala/exercises/exercises/Fibonacci.class
Binary file not shown.