Scala Array of different types of values - scala

Writing a function in Scala that accepts an Array/Tuples/Seq of different types of values and sorts it based on first two values in each:
def sortFunction[T](input: Array[T]) = input(0)+ " " + input(1)
The input values I have are as below:
val data = Array((1, "alpha",88.9), (2, "alpha",77), (2, "beta"), (3, "alpha"), (1, "gamma",99))
Then I call the sortFunction as:
data.sortWith(sortFunction)
It is giving below errors:
- polymorphic expression cannot be instantiated to expected type; found : [T]scala.collection.mutable.Seq[T] ⇒ Int required: ((Int, String)) ⇒ ? Error occurred in an application involving default arguments.
- type mismatch; found : scala.collection.mutable.Seq[T] ⇒ Int required: ((Int, String)) ⇒ ? Error occurred in an application involving default arguments.
What am I doing wrong, or how do I get around this? I would be grateful for any suggestions.

If you know type of element in Array[T], you can use pattern matching (when same type). But If You don't know, Program can't decide how to sort your data.
One of methods is just String compare like below.
object Hello{
def sortFunction[T](input1: T, input2: T) =
input1 match {
case t : Product =>
val t2 = input2.asInstanceOf[Product]
t.productElement(0).toString < t2.productElement(0).toString
case v => input1.toString > input2.toString
}
def main(args: Array[String]): Unit = {
val data = Array((1, "alpha",88.9), (2, "alpha",77), (2, "beta", 99), (3, "alpha"), (1, "gamma",99))
println(data.sortWith(sortFunction).mkString)
}
}
If you want to know Product tarit, see http://www.scala-lang.org/api/rc2/scala/Product.html

If you have an Array of tuples that all have the same arity, such as tuples of (Int, String), than your sort function could look something like
def sortFunction[T](fst: (Int, String), scd: (Int, String)) = fst._1 < scd._1 // sort by first element
However, since you have an Array of tuples of varying arity, Scala compiler can only put this under nearest common type Product. Then you can sort like this:
def sortFunction[T](fst: (Product), scd: (Product)) = fst.productElement(1).toString < scd.productElement(1).toString
val data = Array((1, "alpha", 99), (2, "alpha"), (2, "beta"), (3, "alpha"), (1, "gamma"))
data.sortWith(sortFunction) // List((1,alpha,99), (2,alpha), (3,alpha), (2,beta), (1,gamma))
Note that this is really bad design though. You should create an abstract data type that encapsulates your data in a more structured way. I can't say what it should look like since I don't know where and how you are getting this information, but here's an example (called Foo, but you should of course name it meaningfully):
case class Foo(index: Int, name: String, parameters: List[Int])
I just assumed that the first element in each piece of data is "index" and second one is "name". I also assumed that the rest of those elements inside will always be integers and that there may be zero, one or more of them, so hence a List (if it's only zero or one, better choice would be Option).
Then you could sort as:
def sortFunction[T](fst: Foo, scd: Foo) = fst.index < scd.index
or
def sortFunction[T](fst: Foo, scd: Foo) = fst.name < scd.name

Related

Typesafe keys for a map

Given the following code:
val m: Map[String, Int] = .. // fetch from somewhere
val keys: List[String] = m.keys.toList
val keysSubset: List[String] = ... // choose random keys
We can define the following method:
def sumValues(m: Map[String, Int], ks: List[String]): Int =
ks.map(m).sum
And call this as:
sumValues(m, keysSubset)
However, the problem with sumValues is that if ks happens to have a key not present on the map, the code will still compile but throw an exception at runtime. Ex:
// assume m = Map("two" -> 2, "three" -> 3)
sumValues(m, 1 :: Nil)
What I want instead is a definition for sumValues such that the ks argument should, at compile time, be guaranteed to only contain keys that are present on the map. As such, my guess is that the existing sumValues type signature needs to accept some form of implicit evidence that the ks argument is somehow derived from the list of keys of the map.
I'm not limited to a scala Map however, as any record-like structure would do. The map structure however won't have a hardcoded value, but something derived/passed on as an argument.
Note: I'm not really after summing the values, but more of figuring out a type signature for sumValues whose calls to it can only compile if the ks argument is provably from the list of keys the map (or record-like structure).
Another solution could be to map only the intersection (i.e. : between m keys and ks).
For example :
scala> def sumValues(m: Map[String, Int], ks: List[String]): Int = {
| m.keys.filter(ks.contains).map(m).sum
| }
sumValues: (m: Map[String,Int], ks: List[String])Int
scala> val map = Map("hello" -> 5)
map: scala.collection.immutable.Map[String,Int] = Map(hello -> 5)
scala> sumValues(map, List("hello", "world"))
res1: Int = 5
I think this solution is better than providing a default value because more generic (i.e. : you can use it not only with sums). However, I guess that this solution is less effective in term of performance because the intersection.
EDIT : As #jwvh pointed out in it message below, ks.intersect(m.keys.toSeq).map(m).sum is, to my opinion, more readable than m.keys.filter(ks.contains).map(m).sum.

Reading from CSV file in scala

I have a file in that has different data informations about a certain population.
Example of file format:
1880,Mary,F,7065
1880,Anna,F,2604
1880,Emma,F,2003
1880,Elizabeth,F,1939
We can interpret this data as “In the year 1880, 7065 female babies were born named Mary"
I have a function that reads from the file
fromFile(name:String):List[List[String]]
fromFile returns a list of lists:
List( List("1880","Mary", "F","7065"))
I am having trouble figuring out how to get the data and parsing it out for a function like this, which takes a nested list and a number,and returns a list of of entries of such year.
For example if 'n' is 1880, then the return list would return all info about Mary.
object readFile{
val years = CSV.fromFile("my_file.csv")
def yearIs(data: List[List[String]], n: Int): List[List[String]] =
??
}
I trying to figure out how to access each element in the returned list and compare it to the given 'int', and return all the data.
I would always recommend to first convert input data into a appropriate structure and doing all conversions and possibly error reporting and then do what you want to do on that.
So an appropriate structure for one record would be:
case class Record(year: Int, name: String, female: Boolean, count: Int)
Lets convert your data:
val data = CSV.fromFile("my_file.csv").map {
case List(year, name, female, count) =>
Record(year.toInt, name, female == "F", count.toInt)
}
You should catch a MatchError and a NumberFormatException here or try to detect these error, if you do care about error handling.
Now we can define your method yearIs in a type-safe and concise manner:
def yearIs(data: List[Record], year: Int) = data.filter(_.year == year)
You could also directly create a Map from years to list of recors:
val byYear: Map[Int, List[Record]] = data.record.groupBy(_.year)
I think the best way to get "a list of the years from n onward" is to compare n with the year or first element in the List using filter.
scala> def yearIs(data: List[List[String]], n: Int): List[List[String]] = {
| data.filter(xs => xs.head.toInt > n)
| }
yearIs: (data: List[List[String]], n: Int)List[List[String]]
scala> yearIs(data, 1880)
res6: List[List[String]] = List()
scala> yearIs(data, 1879)
res7: List[List[String]] = List(List(1880, Mary, F, 7065), List(1880, Anna, F, 2604), List(1880, Emma, F, 2003))

passing all arguments to a function as a single array

This is a Scala-specific question.
Assume that you have a function (which you cannot modify) of several inputs, e.g.:
def test(x1: Int, x2:Int, x3: Int, x4: Int, x5: Int) = {
//Some logic
}
And assume that you have all the inputs for that function in a single array, e.g.:
val inputs = Array(1, 2, 3, 4, 5)
Is there a way to call test with that single array of inputs without explicitly inserting individual array elements (as in test(inputs(0),inputs(1),inputs(2),inputs(3),inputs(4)))?
This is particularly important for the case when I don't know the number of inputs and the number of elements in the array in advance (but know that they match).
No that's not possible. It's possible to use an array for a function that expects varargs by using :_* syntax. Also, your question is contradictory:
the case when I don't know the number of inputs and the number of
elements in the array in advance (but know that they match)
How could you not know the number of inputs or elements but know they match?
You can curry the function and then use one of the solutions proposed here.
For instance, using this technique:
class Acc[T](f: Function1[T, _]) {
private[this] var ff: Any = f
def apply(t: T): this.type = {
ff = ff.asInstanceOf[Function1[T,_]](t)
this
}
def get = ff match {
case _: Function1[_,_] => sys.error("not enough arguments")
case res => res.asInstanceOf[T]
}
}
def test(x1: Int, x2:Int, x3: Int, x4: Int, x5: Int) = {
//Some logic
}
val inputs = Array(1, 2, 3, 4, 5)
inputs.foldLeft(new Acc((test _).curried))((acc, i) => acc(i)).get
Not extremely safe, but it should work
You can use Java reflection (or Scala reflection, but Java's one is sufficient for this). The below is a quick and dirty solution, which assumes you have a class Test which contains exactly one test method:
val m = classOf[Test].
getMethods.find(_.getName == "test").
getOrElse(throw new Exception("No method called test"))
// inputs must be Array[Object], not Array[Int] as in your example
m.invoke(instanceOfTest, inputs)
This is rarely a good idea, however.

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.

Checking for greater than on a generic tuple element

I have a method to add different types of tuples to a list with the first tuple element always being an Int. I need to do a "greater than" compare but this is not allowed on an Any type. Can someone tell me how I could achieve the desired effect below?
Thanks
Des
private def add(list: List[Product], item: Product): List[Product] = {
if(list.isEmpty || list.head.productElement(0) > item.productElement(0)) item :: list
else add(list.tail, item)
}
If you can't take ziggystar's suggestion because the Producer has variable arity, you could potentially achieve the desired effect by refactoring with the upside of avoiding a complex and potentially less readable approach. For instance:
case class Item(i: Int, item: Product)
def add(list: List[Item], item: Item): List[Item] = {
if (list.isEmpty || list.head.i > item.i) item :: list
else add(list.tail, item)
}
which, when used, looks like this:
add(Nil, Item(1, (1, "b"))) // List(Item(1,(1,b)))
add(List(Item(1, (1, "a"))), Item(2, (1, "b"))) // List(Item(2,(1,b)))
add(List(Item(2, (1, "a"))), Item(1, (1, "b"))) // List(Item(1,(1,b)), Item(2,(1,a))
If you are willing to resort to reflection, you can use a mixture of nominal and structural typing:
import scala.language.reflectiveCalls
// A structural type exploiting the fact that all tuples have a _1 field
type IntComponent = { val _1: Int }
def add(list: List[Product with IntComponent], item: Product with IntComponent): List[Product with IntComponent] = {
if(list.isEmpty || list.head._1 > item._1) item :: list
else add(list.tail, item)
}
The combination Product with IntComponent is not strictly necessary, IntComponent would suffice. However, the combination gives you a bit more safety, and it allows you to use fields and methods declared by Product if need be.
This gives you quite a bit of static type safety:
add(Nil, (1, "foo", null)) // ok
add(Nil, ("foo", 0)) // error
// error: type mismatch;
// found : String("foo")
// required: Int
add(List[Product with IntComponent](Tuple1(1), Tuple2(-1, true)), (0, "yes"))
// Explicit type annotation required, error otherwise
// found : List[Product with Serializable]
// required: List[Product with this.IntComponent]
The obvious weakness of this approach is, that you can sneak in any object that is a Product with IntComponent, for example
case class FakeTupleA(_1: Int)
add(Nil, FakeTupleA(99)) // ok
Without the Product requirement, the following would also work:
add(Nil, new FakeTupleB(99))
// error: type mismatch;
// found : this.FakeTupleB
// required: Product with this.IntComponent