Indexing/Slicing of Collections in Scala - scala

I saw some really cool methods to operate on Scala Collections but I wanted to know how can one do the slicing operation in Scala? I see methods like dropLeft take but curious to know if something simpler like indexing or slice exists in Scala.
For example:
val aString = "I want this word"
val aList = List(1,2,3,4)
should return:
val slicedString = aString.slice(7,11) => "this" //JavaScript type
and
val slicedList = aList.slice(0,2) => List(1,2) //JavaScript type
or indexing like how it's done in python:
val slicedString = aString(7:11) => "this"
val slicedList = aList(0:2) => List(1,2)

Had you bothered to consult the ScalaDocs you would have found what you're looking for.
aString.slice(7,11) //res0: String = this
aList.slice(0,2) //res1: List[Int] = List(1, 2)

Related

How would I alter a list within a list in Scala using functional programming

Imagine I have a list[list[object]]
and I wanted to get a list[list[object.field]]
How would i be able to do this through functional programming
as in
if val list = list[list[object]]
i tried
val newList = list(_)(_1.map(object.field))
but this gave me an error and I am confused
I just started functional programming and scala so there might be something completely illogical with this statement
You need to use map as following
case class Obj(field: String)
val list = List[List[Obj]]()
val fields: List[List[String]] = list.map(_.map(_.field))
or same as
val fields: List[List[String]] = list.map(innerList => innerList.map(obj => obj.field))
or if you want to have a flattened list of fields
val fields: List[String] = list.flatMap(_.map(_.field))

scala: list as input and output of function

I am new to scala. I have a very simple problem.
Given a list in python
x=[1, 100, "a1", "b1"]
I can write a function that will return the last two elements
def f(w):
if w[0]>=1 and w[1]<=100:
return ([w[2],w[3]])
How do I do the equivalent in scala
val v= List(1, 100, "a1", "b1")
def g(L:List[Any]): List[String] = {
if( L(0)>=1 & L(1)<=100 ) {return List(L(2), L(3))}
}
val w=g(v)
This gets me the error
List[Any] = List(1, 100, a, b)
Incomplete expression
You can't get a List[String] from a List[Any]. (Well, you can, but it's a really bad thing to do.)
Don't, don't, don't create a List[Any]. Unlike Python, Scala is a strictly typed language, which means that the compiler keeps a close watch on the type of each variable and every collection. When the compiler looses track of the List type it becomes List[Any] and you've lost all the assistance the compiler offers to help write programs that don't crash.
To mix types in a collection you can use tuples. Here's the type-safe Scala way to write your g() method.
def g(tup: (Int,Int,String,String)): List[String] =
if (tup._1 >= 1 & tup._2 <= 100) List(tup._3, tup._4)
else List()
Usage:
val v = (1, 100, "a1", "b1")
val w = g(v) //w: List[String] = List(a1, b1)
It seems like you have a typo here:
if(L(0)>=1 & L(1<=100)) {return List(L(2), L(3))}
Wouldn't it be like this?
if(L(0)>=1 & L(1)<=100) {return List(L(2), L(3))}
The error seems to point out there's something wrong with that extra bracket there.
scala> List(1,2,3,4,5).takeRight(2)
res44: List[Int] = List(4, 5)
You can use a built in function in Scala that does this!

How to turn a list of objects into a map of two fields in Scala

I'm having a real brain fart here. I'm working with the Play Framework. I have a method which takes a map and turns it into a HTML select element. I had a one-liner to take a list of objects and convert it into a map of two of the object's fields, id and name. However, I'm a Java programmer and my Scala is weak, and I've only gone and forgotten the syntax of how I did it.
I had something like
organizations.all.map {org => /* org.prop1, org.prop2 */ }
Can anyone complete the commented part?
I would suggest:
map { org => (org.id, org.name) } toMap
e.g.
scala> case class T(val a : Int, val b : String)
defined class T
scala> List(T(1, "A"), T(2, "B"))
res0: List[T] = List(T(1,A), T(2,B))
scala> res0.map(t => (t.a, t.b))
res1: List[(Int, String)] = List((1,A), (2,B))
scala> res0.map(t => (t.a, t.b)).toMap
res2: scala.collection.immutable.Map[Int,String] = Map(1 -> A, 2 -> B)
You could also take an intermediary List out of the equation and go straight to the Map like this:
case class Org(prop1:String, prop2:Int)
val list = List(Org("foo", 1), Org("bar", 2))
val map:Map[String,Int] = list.map(org => (org.prop1, org.prop2))(collection.breakOut)
Using collection.breakOut as the implicit CanBuildFrom allows you to basically skip a step in the process of getting a Map from a List.

Scala, Casbah - How to convert List to MongoDBList?

Is there an easy way to turn List into MongoDBList(or BasicDBList) ?
scala> val list = List("foo", "bar")
list: List[java.lang.String] = List(foo, bar)
scala> val dbList = MongoDBList(list:_*)
dbList: com.mongodb.casbah.commons.MongoDBList = [ "foo" , "bar"]
Hint: always read source code at first. It can provide many answers to your questions and will be useful BTW. It may be hard at first time, but then it became more and more natural.

Scala collections: Is there a safe map operation?

Let's say that I have a List (or the values in a Map), and i want to perform an operation on each item. But unfortunately, for whatever reason, this list of values can contain nulls.
scala> val players = List("Messi", null, "Xavi", "Iniesta", null)
players: List[java.lang.String] = List(Messi, null, Xavi, Iniesta, null)
In order to avoid blowing up with a NPE, i need to do the following:
scala> players.filterNot(_ == null ).map(_.toUpperCase)
res84: List[java.lang.String] = List(MESSI, XAVI, INIESTA)
Is there any better way of doing this?
Ideally something like:
players.safeMap(_.toUpperCase)
On the scala-language mailing list, Simon proposed this:
players.filter ( null !=).map(_.toUpperCase )
which is shorter version of my original take, and as short as you can get without a dedicated method.
Even better, Stefan and Kevin proposed the method withFilter which will return a lazy proxy, so both operations can be merged.
players.withFilter ( null !=).map(_.toUpperCase )
If you can’t avoid nulls (e.g. if you get your list from Java code), another alternative is to use collect instead of map:
scala> players.collect { case player if player != null => player.toUpperCase }
res0: List[java.lang.String] = List(MESSI, XAVI, INIESTA)
I'd do this:
players flatMap Option map (_.toUpperCase)
But that's worse than collect. filter + map is always better done with collect.
You could convert to a list of Option[String]:
scala> val optionPlayers = players.map(Option(_))
optionPlayers: List[Option[java.lang.String]] = List(Some(Messi), None, Some(Xavi), Some(Iniesta), None)
Option is universally preferred to null and it gives you a lot of flexibility in how you can safely handle the data. Here's are thee easy ways to get the result you were looking for:
scala> optionPlayers.collect { case Some(s) => s.toUpperCase }
res0: List[java.lang.String] = List(MESSI, XAVI, INIESTA)
scala> optionPlayers.flatMap(_.map(_.toUpperCase))
res1: List[java.lang.String] = List(MESSI, XAVI, INIESTA)
scala> optionPlayers.flatten.map(_.toUpperCase)
res2: List[java.lang.String] = List(MESSI, XAVI, INIESTA)
You can find a lot more information about Option in other StackOverflow questions or by searching the web.
Or, you can always just define that safeMap method you wanted as an implicit on List:
implicit def enhanceList[T](list: List[T]) = new {
def safeMap[R](f: T => R) = list.filterNot(_ == null).map(f)
}
so you can do:
scala> players.safeMap(_.toUpperCase)
res4: List[java.lang.String] = List(MESSI, XAVI, INIESTA)
Though if you define an implicit, you might want to use a CanBuildFrom style like the basic collections do to make it work on more than just List. You can find more information about that elsewhere.