SML Comparing datatype list and hd() tl() function - smlnj

For 2 datatype like this.
datatype flight = F of int * int;
datatype flights = Fs of flight list;
I want to make a function that can check if (a,b) is in flights or not.
Example:
val reachable = fn : flights * (int * int) -> bool
reachable (Fs [F(0,1), F(1,0)], (0, 1));
val it = true : bool
I have no idea how can i compare a (int*int) to flights.
I use
fun get_f_x (F(x,y)) = x;
to get the first integer in flight.
But when i try to do the same thing to flights.
I do it like below:
fun test_hd(Fs[i,_]) = i;
In order to get the first flight out for the flights.
But it can only take flights with 2 flight only (Fs [F(0,1), F(1,0)])
If flight have more than 2 element, it show error.
Similarly
fun test_tl(Fs[_,i]) = i;
have the same problem.
How can I make a hd and tl for flights? Or what is the correct way to think about this problem?

Not having seen the errors you're encountering, it's hard to say, but looking at the code you've shown, I suspect in-exhaustive pattern matching is a factor. With that in mind, let's look at a way of breaking down the recursion and pattern matching involved.
If you want to see if a particular flight is in flights, first we need to start with what we absolutely know: If a flights value contains no values in its list, then the answer must be false, no matter what we're looking for.
fun reachable(Fs([]), _) = false
What if there is something in that list? Well, let's check the first element to see if it's what we are looking for.
fun reachable(Fs([]), _) = false
| reachable(Fs(F(x) :: xs), flt) = flt = x
But what about the rest, if that one doesn't match? We'd need to check the rest of the list.
fun reachable(Fs([]), _) = false
| reachable(Fs(F(x) :: xs), flt) =
flt = x orelse reachable(Fs(xs), flt)

Related

Updating object value after applying Filter in Scala

I am having List of List's and calling it BAT in my code. Each BAT has 2 attribute. First one is Position and second is fitness. For Every List in BAT , i am computing its fitness using Sphere function. Based on fitness i have applied Filter which filter only those list whom fitness is less than a object called GF. This return me BAT.
My code is
var GlobalBest_Fitness = Double.PositiveInfinit
var BAT = List.fill(N)(new BAT1(d, MinVal, MaxVal))
BAT.map { x =>
x.fitness = sphere(x.position)
}
BAT.filter(_.Fitness < GF).map { x =>
GF = x.Fitness
}
def sphere(list: List[Double]): Double = {
list.foldLeft(0.0)((x, xs) => x + xs * xs)
}
class BAT1 ( dim:Int , min:Double , max:Double) {
val random = new Random()
var position : List[Double] = List.fill(dim)(random.nextDouble() * (max-min)+min )
var fitness :Double = math.random
}
This code set GF Fitness of last member of BAT but i want to set value of Object GF to Fitness of List with Lowest Fitness.
Here is some output to explain question. BAT with 5 Lists,
(List(-67.33460898977961, -71.09215709663737, 55.89607430834903, -43.23771807116002),14581.91575554507)
(List(90.12684307743376, 43.946793301728036, -93.06789837138616, -76.86083905559525),24623.390772205956)
(List(12.619843833260006, -86.17961848282789, 48.99208107528267, 24.69991428409682),10596.496873950442)
(List(96.24721330545535, 54.598176031247306, -92.20930457845513, -42.450241098519385),22549.06571516962)
(List(71.10095207554104, 74.02738064902607, 93.76767384566747, 40.917896190085656),21002.04935885428)
Output ==>> GF = 21002.04935885428
This is seting value of GF to last List fitness, it should instead set it to Lowest value that is 10596.496873950442 that is fitness of third List.
This List could be very large and have to iterate over it millions of time. I want to find optimal solution.
According to what I understood from the question, you want a minimum fitness value from a List of BAT1 objects ( List[BAT1] ).
Problems noticed:
No need to set fitness later by mapping, .map is used for
transformation of a list/collection/monad (e.g., you want to convert a
List[A] to List[B]).
So, your BAT1 class should look like:
class BAT1(dim:Int, min:Double, max:Double) {
val random = new Random()
var position: List[Double] = List.fill(dim)(random.nextDouble() * (max-min)+min )
val fitness: Double = sphere(position) //no need of var and can be directly computer here only
}
To get the lowest fitness, you don't need to filter
val minFitness = BAT.map(_.fitness).min
/*
we will first convert the list BAT which has type List[BAT1] to a
List[Double] containing fitness of each BAT1 object in the list
we will then get the minimum value in the List[Double] by .min method
List[BAT1] -> List[Double] -> Double
*/
Another way:
val minFitness = BAT.minBy(_.fitness).fitness //please read about minBy, maxBy in Scala documentations.

What is the scala equivalent of Python's Numpy np.random.choice?(Random weighted selection in scala)

I was looking for Scala's equivalent code or underlying theory for pythons np.random.choice (Numpy as np). I have a similar implementation that uses Python's np.random.choice method to select the random moves from the probability distribution.
Python's code
Input list: ['pooh', 'rabbit', 'piglet', 'Christopher'] and probabilies: [0.5, 0.1, 0.1, 0.3]
I want to select one of the value from the input list given the associated probability of each input element.
The Scala standard library has no equivalent to np.random.choice but it shouldn't be too difficult to build your own, depending on which options/features you want to emulate.
Here, for example, is a way to get an infinite Stream of submitted items, with the probability of any one item weighted relative to the others.
def weightedSelect[T](input :(T,Int)*): Stream[T] = {
val items :Seq[T] = input.flatMap{x => Seq.fill(x._2)(x._1)}
def output :Stream[T] = util.Random.shuffle(items).toStream #::: output
output
}
With this each input item is given with a multiplier. So to get an infinite pseudorandom selection of the characters c and v, with c coming up 3/5ths of the time and v coming up 2/5ths of the time:
val cvs = weightedSelect(('c',3),('v',2))
Thus the rough equivalent of the np.random.choice(aa_milne_arr,5,p=[0.5,0.1,0.1,0.3]) example would be:
weightedSelect("pooh"-> 5
,"rabbit" -> 1
,"piglet" -> 1
,"Christopher" -> 3).take(5).toArray
Or perhaps you want a better (less pseudo) random distribution that might be heavily lopsided.
def weightedSelect[T](items :Seq[T], distribution :Seq[Double]) :Stream[T] = {
assert(items.length == distribution.length)
assert(math.abs(1.0 - distribution.sum) < 0.001) // must be at least close
val dsums :Seq[Double] = distribution.scanLeft(0.0)(_+_).tail
val distro :Seq[Double] = dsums.init :+ 1.1 // close a possible gap
Stream.continually(items(distro.indexWhere(_ > util.Random.nextDouble())))
}
The result is still an infinite Stream of the specified elements but the passed-in arguments are a bit different.
val choices :Stream[String] = weightedSelect( List("this" , "that")
, Array(4998/5000.0, 2/5000.0))
// let's test the distribution
val (choiceA, choiceB) = choices.take(10000).partition(_ == "this")
choiceA.length //res0: Int = 9995
choiceB.length //res1: Int = 5 (not bad)

Scala - conditionally sum elements in list

I am trying to solve a beginner problem with lists but can't find an example to help me get it work. I am given a list of positive and negative integers (AccountHistory) and I need to check if the negative integers in this list have ever exceeded -1000. I expected my code to work with a freshly introduced helper function like this:
def checkAccount(account: AccountHistory): Boolean = {
def helper(i: AccountHistory): Int = {
var total = 0
i.collect{case x if x < 0 => Math.abs(x) + total}
return total
}
if (helper(account) >1000) true else false
}
But it doesn't work. Please help me find my mistake or problem in wrong approach.
Edit: The pre-given tests include
assert(checkAccount(List(10,-5,20)))
assert(!checkAccount(List(-1000,-1)))
So if assert expects true then my approach is wrong to solve it like this.
By 'exceeded' I mean <-1000, for any or all elements in a list (like exceeding a credit amount in given period).
i.collect{case x if x < 0 => Math.abs(x) + total}
In the above code snippet, not assign back to total, maybe you need:
val total = i.filter(_ < 0).map(Math.abs).sum
I think this is what you're supposed to do:
def checkAccount(account: AccountHistory): Boolean =
account.forall(_ > -1000)

Variable not updated

This is perhaps very basic but I am certainly missing something here.
It is all within a method, where I increment/alter a variable within a child/sub scope (it could be within a if block, or like here, within a map)
However, the result is unchanged variable. e.g. here, sum remains zero after the map. whereas, it should come up to 3L.
What am I missing ?
val resultsMap = scala.collection.mutable.Map.empty[String, Long]
resultsMap("0001") = 0L
resultsMap("0003") = 2L
resultsMap("0007") = 1L
var sum = 0L
resultsMap.mapValues(x => {sum = sum + x})
// I first wrote this, but then got worried and wrote more explicit version too, same behaviour
// resultMap.mapValues(sum+=_)
println("total of counts for txn ="+sum) // sum still 0
-- Update
I have similar behaviour where a loop is not updating the variable outside the loop. looking for text on variable scoping, but not found the golden source yet. all help is appreciated.
var cnt : Int = 0
rdd.foreach(article => {
if (<something>) {
println(<something>) // being printed
cnt += 1
println("counter is now "+cnt) // printed correctly
}
})
You should proceed like this:
val sum = resultsMap.values.reduce(_+_)
You just get your values and then add them up with reduce.
EDIT:
The reason sum stays unchanged is that mapValues produces a view, which means (among other things) the new map won't be computed unless the resulting view is acted upon, so in this case - the code block updating sum is simply never executed.
To see this - you can "force" the view to "materialize" (compute the new map) and see that sum is updated, as expected:
var sum = 0L
resultsMap.mapValues(x => {sum = sum + x}).view.force
println("SUM: " + sum) // prints 3
See related discussion here: Scala: Why mapValues produces a view and is there any stable alternatives?

Consolidating a data table in Scala

I am working on a small data analysis tool, and practicing/learning Scala in the process. However I got stuck at a small problem.
Assume data of type:
X Gr1 x_11 ... x_1n
X Gr2 x_21 ... x_2n
..
X GrK x_k1 ... x_kn
Y Gr1 y_11 ... y_1n
Y Gr3 y_31 ... y_3n
..
Y Gr(K-1) ...
Here I have entries (X,Y...) that may or may not exist in up to K groups, with a series of values for each group. What I want to do is pretty simple (in theory), I would like to consolidate the rows that belong to the same "entity" in different groups. so instead of multiple lines that start with X, I want to have one row with all values from x_11 to x_kn in columns.
What makes things complicated however is that not all entities exist in all groups. So wherever there's "missing data" I would like to pad with for instance zeroes, or some string that denotes a missing value. So if I have (X,Y,Z) in up to 3 groups, the type I table I want to have is as follows:
X x_11 x_12 x_21 x_22 x_31 x_32
Y y_11 y_12 N/A N/A y_31 y_32
Z N/A N/A z_21 z_22 N/A N/A
I have been stuck trying to figure this out, is there a smart way to use List functions to solve this?
I wrote this simple loop:
for {
(id, hitlist) <- hits.groupBy(_.acc)
h <- hitlist
} println(id + "\t" + h.sampleId + "\t" + h.ratios.mkString("\t"))
to able to generate the tables that look like the example above. Note that, my original data is of a different format and layout,but that has little to do with the problem at hand, thus I have skipped all steps regarding parsing. I should be able to use groupBy in a better way that actually solves this for me, but I can't seem to get there.
Then I modified my loop mapping the hits to ratios and appending them to one another:
for ((id, hitlist) <- hits.groupBy(_.acc)){
val l = hitlist.map(_.ratios).foldRight(List[Double]()){
(l1: List[Double], l2: List[Double]) => l1 ::: l2
}
println(id + "\t" + l.mkString("\t"))
//println(id + "\t" + h.sampleId + "\t" + h.ratios.mkString("\t"))
}
That gets me one step closer but still no cigar! Instead of a fully padded "matrix" I get a jagged table. Taking the example above:
X x_11 x_12 x_21 x_22 x_31 x_32
Y y_11 y_12 y_31 y_32
Z z_21 z_22
Any ideas as to how I can pad the table so that values from respective groups are aligned with one another? I should be able to use _.sampleId, which holds the "group membersip" for each "hit", but I am not sure how exactly. ´hits´ is a List of type Hit which is practically a wrapper for each row, giving convenience methods for getting individual values, so essentially a tuple which have "named indices" (such as .acc, .sampleId..)
(I would like to solve this problem without hardcoding the number of groups, as it might change from case to case)
Thanks!
This is a bit of a contrived example, but I think you can see where this is going:
case class Hit(acc:String, subAcc:String, value:Int)
val hits = List(Hit("X", "x_11", 1), Hit("X", "x_21", 2), Hit("X", "x_31", 3))
val kMax = 4
val nMax = 2
for {
(id, hitlist) <- hits.groupBy(_.acc)
k <- 1 to kMax
n <- 1 to nMax
} yield {
val subId = "x_%s%s".format(k, n)
val row = hitlist.find(h => h.subAcc == subId).getOrElse(Hit(id, subId, 0))
println(row)
}
//Prints
Hit(X,x_11,1)
Hit(X,x_12,0)
Hit(X,x_21,2)
Hit(X,x_22,0)
Hit(X,x_31,3)
Hit(X,x_32,0)
Hit(X,x_41,0)
Hit(X,x_42,0)
If you provide more information on your hits lists then we could probably come with something a little more accurate.
I have managed to solve this problem with the following code, I am putting it here as an answer in case someone else runs into a similar problem and requires some help. The use of find() from Noah's answer was definitely very useful, so do give him a +1 in case this code snippet helps you out.
val samples = hits.groupBy(_.sampleId).keys.toList.sorted
for ((id, hitlist) <- hits.groupBy(_.acc)) {
val ratios =
for (sample <- samples)
yield hitlist.find(h => h.sampleId == sample).map(_.ratios)
.getOrElse(List(Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN))
println(id + "\t" + ratios.flatten.mkString("\t"))
}
I figure it's not a very elegant or efficient solution, as I have two calls to groupBy and I would be interested to see better solutions to this problem.