Erlang - If Else Condition - if-statement

Trying to compute a score and maintain it between a range 0.2 to 1.5 .
Will the below code work ? I don't want it to return, but continue further.
ok = if
Score > 1.5 ->
Score = 1.5;
true ->
ok
end,
ok = if
Score < 0.2 ->
Score = 0.2;
true ->
ok
end,
put(score, Score),

Will the below code work ?
No. In erlang, you can only assign to a variable once. That is one of the first things you should have learned. In this statement:
if
Score > 1.5 -> ...
the variable Score will already have been assigned a value, which you are comparing to the decimal 1.5. Suppose the value of Score is 2.0, so that the body of that particular if clause executes:
Score = 1.5;
That is equivalent to writing:
2.0 = 1.5;
which will result in a pattern match error:
exception error: no match of right hand side value 1.5.
In erlang, once you assign a value to a variable, thereafter any subsequent assignment to that variable will be treated as a pattern match, i.e. the value on the right of the equals sign will be pattern matched against the value on the left of the equals sign.
In erlang, you typically use multiple function clauses to pattern match different values:
-module(my).
-compile(export_all).
compute(Score) when Score > 1.5 ->
1.5;
compute(Score) when Score < 0.2 ->
0.2;
compute(Score) ->
Score.
In the shell:
1> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> Score1 = my:compute(1.6).
1.5
3> Score2 = my:compute(1.5).
1.5
4> Score3 = my:compute(1.2).
1.2
5> Score4 = my:compute(0.1).
0.2
6> Score5 = my:compute(0.2).
0.2
Then you can define another function in the same module like this:
do_stuff(Score) ->
NewScore = compute(Score),
%Do something with NewScore here...
If you want to use an if-statement, I would do it like this:
-module(my).
-compile(export_all).
do_stuff(Score) ->
NewScore = if
Score > 1.5 -> 1.5;
Score < 0.2 -> 0.2;
true -> Score
end,
%Do something with NewScore here, for instance:
io:format("~w~n", [NewScore]).
In an effort to keep your functions no longer than 5-6 lines, it would help to move that if-statement into another function.

Another approach is to use erlang:min/2 and erlang:max/2 to maintain the range:
-module(my).
-compile(export_all).
do_stuff(Score) ->
max(min(Score, 1.5), 0.2).
If Score is greater than 1.5, min/2 will return 1.5, else Score. Then, if that result is less than 0.2, max/2 will return 0.2, else the result of min/2. Here's our test function:
test_do_stuff() ->
ScoresAndResults = [{0, 0.2},
{1.5, 1.5},
{0.2, 0.2},
{1.4999999, 1.4999999},
{1.5000001, 1.5},
{42, 1.5},
{0.19999999, 0.2},
{0.2000000000001, 0.2000000000001},
{1.2, 1.2},
{1, 1},
{-1, 0.2}],
{Scores, Results} = lists:unzip(ScoresAndResults),
Results = [do_stuff(Score) || Score <- Scores].
Running it produces the expected results:
1> my:test_do_stuff().
[0.2,1.5,0.2,1.4999999,1.5,1.5,0.2,0.2000000000001,1.2,1,0.2]

Related

how can I combine a cell array and two scalars to obtain a cell array of string, scalar1, scalar2 elements in Octave avoiding loops?

I have a cell array like P and two other float variables
P = {"GG+G[G]", "GG", "GG-GGG", "GG[][GG]", "[G[GG-G]]", "G[GG]+[G]"};
val1 = 0.01;
val2 = 0.3;
And I would like to build the following data structure without using a loop because the P cell array can contain a large number of elements:
Inputparam =
{
[1,1] = {
[1,1] = "GG+G[G]"
[1,2] = 0.01
[1,3] = 0.3
}
[1,2] = {
[1,1] = "GG"
[1,2] = 0.01
[1,3] = 0.3
}
[1,3] = {
[1,1] = "GG-GGG"
[1,2] = 0.01
[1,3] = 0.3
}
[1,4] = {
[1,1] = "GG[][GG]"
[1,2] = 0.01
[1,3] = 0.3
}
[1,5] = {
[1,1] = "[G[GG-G]]"
[1,2] = 0.01
[1,3] = 0.3
}
[1,6] = {
[1,1] = "G[GG]+[G]"
[1,2] = 0.01
[1,3] = 0.3
}
}
I've tried several options but with most of them what I got was a concatenation and not a combination of the elements.
The purpose of this structure is to be the argument of parcellfun function that's why I need to have each element of P, with val1 and val2 values.
I'm also considering using an anonymum function instead of allocation all this data in memory. does it make sense?
thanks in advance.
I suggest that, instead of a cell array of cells arrays, you create a 2D cell array, just because this is much easier to generate and, for large arrays, it takes up less memory too:
P = {"GG+G[G]", "GG", "GG-GGG", "GG[][GG]", "[G[GG-G]]", "G[GG]+[G]"};
P(2,:) = 0.01;
P(3,:) = 0.2;
The cell array is indexed using P{1,5}, rather than P{5}{1} as the cell array in the OP.
Another alternative is to use struct arrays:
P = {"GG+G[G]", "GG", "GG-GGG", "GG[][GG]", "[G[GG-G]]", "G[GG]+[G]"};
P = struct('name',P,'val1',0.01,'val2',0.2);
The struct is indexed as P(5).name rather than P{5}{1} (and P(5).val1 instead of P{5}{2}, etc.).

Scala: Calculating the Moving Sum of a List with a fixed window

I am new to Scala and I want to calculate a moving sum with a fixed window for a list.
For example: Given the list values (1.0, 2.0, 3.0, 6.0, 7.0, 8.0, 12.0, 9.0, 4.0, 1.0), and the period 4, the function should return:
(1.0, 3.0, 6.0, 12.0, 18.0, 24.0, 33.0, 36.0, 33.0, 26.0)
If list.size < period then just return cumulative sum.
I have made some attempts
def mavg(values: List[Double], period: Int): List[Double] = {
if (values.size <= period) (values.sum ) :: List.fill(period -1)(values.sum ) else {
val rest: List[Double] = mavg(values.tail, period)
(rest.head + ((values.head - values(period)))):: rest
}
}
However, I got
List(12.0, 18.0, 24.0, 33.0, 36.0, 33.0, 26.0, 26.0, 26.0, 26.0
which is not correct. I dont want to use Pyspark to get the results. Can someone help?
Many thanks.
def mavg(values: Seq[Double], period: Int): Seq[Double] = {
(Seq.fill(math.min(period - 1, values.length))(0.0) ++ values) // padding zeros
.sliding(period)
.map(_.sum)
.toSeq
}
Here's one way to tackle it.
def mavg(values: List[Double], period: Int): List[Double] =
values.inits //shrinking list of inits
.toList //result type
.reverse //growing list of inits
.tail //drop the empty one
.map(_.takeRight(period).sum) //sum the window
testing:
mavg(List(1.0, 2.0, 3.0, 6.0, 7.0, 8.0, 12.0, 9.0, 4.0, 1.0), 4)
//res0: List[Double] = List(1.0, 3.0, 6.0, 12.0, 18.0, 24.0, 33.0, 36.0, 33.0, 26.0)
This is another way you can do this:
val l = List(1.0, 2.0, 3.0, 6.0, 7.0, 8.0, 12.0, 9.0, 4.0, 1.0,5.0,1.0,2.0)
def mavg(step: Int, list: List[Double], ans: List[Double] = List.empty[Double], splitCount: Int = 0): List[Double] = {
if (list.length > 1) {
mavg(step - 1, list.take(step), list.sliding(step, 1).toList.map(_.sum) ::: ans, splitCount + 1)
} else {
ans.splitAt(splitCount + 2)._1.sliding(1, 2).toList.flatten ::: ans.drop(splitCount + 2)
}
}
val ans = mavg(4, l)
println(ans)
Another approach, similar to the answer by #User9123
The difference is it doesn't calculate the sum of all elements in the sliding window, rather it subtracts the value of the last windows head from its sum and adds the value of the next windows head to yield the next rolling sum. This should be more efficient for large windows.
def rollingSum[N](values: Seq[N], period: Int)(
implicit num: Numeric[N]
): Seq[N] = {
import num._
values match {
case values if period == 1 => values // Can't slide on period 1
case head :: tail if period < values.size =>
(Seq.fill(period - 2)(num.zero) ++ (values)) // zero padding
.sliding(period)
.foldLeft((num.zero, Seq(head))) { // Use a tuple to store previous head
case ((prevHead, acc), y) => {
(y.head, acc :+ acc.last - prevHead + y.last) // do the magic
}
}
._2 // only return the result
case head :: tail => tail.scanLeft(head)(_ + _) // Regular cummulative sum
case Nil => Nil
}
}
I also added some guards for special cases that need to be handled and made it a generic function for all Numeric types.
Here's a running example with some test cases.

How to randomly generate an Oct-Tuple with SML

Edit: Here is the code I have so far for generating the Patient Oct-Tuples.
(thanks Anon for giving me the bost on how to calculate weighted probability/setting the seed)
fun genPatients(x:int) =
let
val seed=let
val m=Date.minute(Date.fromTimeLocal(Time.now()))
val s=Date.second(Date.fromTimeLocal(Time.now()))
in Random.rand(m,s)
end;
val survivalrate = ref(1)
val numl = ref(1)
val td = ref(1)
val xray = ref(false)
val count= ref(0)
val emnum= ref(1000)
val ageList = [1, 2, 3, 3];
val xrayList=[false,true];
val age = Random.randRange (0, 3) seed;(* random age*)
val nextInt1 = Random.randRange(0, 1)(* random xray*)
val r1 = Random.rand(1,1)
val nextInt2 = Random.randRange(1, 10000000)(* random td*)
val r2 = Random.rand(1,1)
val r1hold= ref(1);
in
while !count < x do
(
count:= !count + 1;
List.nth(ageList, age);
r1hold:= nextInt1 r1;
td:= nextInt2 r2;
(!emnum,age,survivalrate,numl,[],[],xray,td);
emnum:= !emnum + 1
)
end;
My question now is now how to go about indexing a boolean list?
So I was looking for some help defining my Oct-tuple to finish up my project and lo and behold I find someone posting the entirety of my project hoping for a handout answer. Not only that, but I'm almost certain we're in the same class, and you think posting this the night before the morning the project is due is what a responsible student does? Pretty sure nobody on SO is gonna do your homework for you anyway, in fact I'm not even sure it's allowed.
Maybe do some work and then ask for help when you've actually done anything. Or maybe in the next phase try a little harder.
EDIT: I'll give you something to get you started.
To calculate weighted probability you need a seed.
val seed=let
val m=Date.minute(Date.fromTimeLocal(Time.now()))
val s=Date.second(Date.fromTimeLocal(Time.now()))
in Random.rand(m,s)
end;
Here's one. Then you can calculate probability, at least for the age, like this:
val ageList = [1, 2, 3, 3];
val ageInt = Random.randRange (0, 3) seed;
List.nth(ageList, ageInt)
This was how I decided to do the weighted probability portion, you can equate this to the other weighted sections if you're creative. Good luck.

Power BI: Multiple condition in single if condition

I have table with the fields Amount, Condition1, Condition2.
Example:
Amount Condition1 Condition2
----------------------------------
123 Yes Yes
234 No Yes
900 Yes No
I want to calculate the 20% of the amount based on condition:
If both Condition1 and Condition2 is Yes then calculate 20% else 0.
My try: I tried with conditional custom column but unable to add AND in IF in the query editor.
You can write a conditional column like this:
= IF(AND(Table1[Condition1] = "Yes", Table1[Condition2] = "Yes"), 0.2 * Table1[Amount], 0)
Or you can use && instead of the AND function:
= IF(Table1[Condition1] = "Yes" && Table1[Condition2] = "Yes", 0.2 * Table1[Amount], 0)
Or an even shorter version using concatenation:
= IF(Table1[Condition1] & Table1[Condition2] = "YesYes", 0.2 * Table1[Amount], 0)
Try to create a new calculated column.
And Use below DAX query:
new_column = IF(Conditition1 = "Yes", IF(Condititon2 = "Yes",Amt * 0.2 ,0), 0)

difflib.get_close_matches GET SCORE

I am trying to get the score of the best match using difflib.get_close_matches:
import difflib
best_match = difflib.get_close_matches(str,str_list,1)[0]
I know of the option to add 'cutoff' parameter, but couldn't find out how to get the actual score after setting the threshold.
Am I missing something? Is there a better solution to match unicode strings?
I found that difflib.get_close_matches is the simplest way for matching/fuzzy-matching strings. But there are a few other more advanced libraries like fuzzywuzzy as you mentioned in the comments.
But if you want to use difflib, you can use difflib.SequenceMatcher to get the score as follows:
import difflib
my_str = 'apple'
str_list = ['ape' , 'fjsdf', 'aerewtg', 'dgyow', 'paepd']
best_match = difflib.get_close_matches(my_str,str_list,1)[0]
score = difflib.SequenceMatcher(None, my_str, best_match).ratio()
In this example, the best match between 'apple' and the list is 'ape' and the score is 0.75.
You can also loop through the list and compute all the scores to check:
for word in str_list:
print "score for: " + my_str + " vs. " + word + " = " + str(difflib.SequenceMatcher(None, my_str, word).ratio())
For this example, you get the following:
score for: apple vs. ape = 0.75
score for: apple vs. fjsdf = 0.0
score for: apple vs. aerewtg = 0.333333333333
score for: apple vs. dgyow = 0.0
score for: apple vs. paepd = 0.4
Documentation for difflib can be found here: https://docs.python.org/2/library/difflib.html
To answer the question, the usual route would be to obtain the comparative score for a match returned by get_close_matches() individually in this manner:
match_ratio = difflib.SequenceMatcher(None, 'aple', 'apple').ratio()
Here's a way that increases speed in my case by about 10% ...
I'm using get_close_matches() for spellcheck, it runs SequenceMatcher() under the hood but strips the scores returning just a list of matching strings. Normally.
But with a small change in Lib/difflib.py currently around line 736 the return can be a dictionary with scores as values, thus no need to run SequenceMatcher again on each list item to obtain their score ratios. In the examples I've shortened the output float values for clarity (like 0.8888888888888888 to 0.889). Input n=7 says to limit the return items to 7 if there are more than 7, i.e. the highest 7, and that could apply if candidates are many.
Current mere list return
In this example result would normally be like ['apple', 'staple', 'able', 'lapel']
... at the default cutoff of .6 if omitted (as in Ben's answer, no judgement).
The change
in difflib.py is simple (this line to the right shows the original):
return {v: k for (k, v) in result} # hack to return dict with scores instead of list, original was ... [x for score, x in result]
New dictionary return
includes scores like {'apple': 0.889, 'staple': 0.8, 'able': 0.75, 'lapel': 0.667}
>>> to_match = 'aple'
>>> candidates = ['lapel', 'staple', 'zoo', 'able', 'apple', 'appealing']
Increasing minimum score cutoff/threshold from .4 to .8:
>>> difflib.get_close_matches(to_match, candidates, n=7, cutoff=.4)
{'apple': 0.889, 'staple': 0.8, 'able': 0.75, 'lapel': 0.667, 'appealing': 0.461}
>>> difflib.get_close_matches(to_match, candidates, n=7, cutoff=.7)
{'apple': 0.889, 'staple': 0.8, 'able': 0.75}
>>> difflib.get_close_matches(to_match, candidates, n=7, cutoff=.8)
{'apple': 0.889, 'staple': 0.8}