Kotlin replace isEmpty()&last() with lastOrNull() within a Collection - list

I would like to use something like (code below), but I think that there must be a nicer solution with usage lastOrNull() instead of using isEmpty and last()
data class Entry(val x: Float, val y: Float)
var entries: MutableList<Entry> = ArrayList()
if(some) {
entries.add(Entry(100f, 200f)
}
val foo = (if (entries.isEmpty()) 0f else entries.last().y) + 100f
Is there some better way like entries.lastOrNull()?.y if null 0f?

you can using Kotlin elvis operator ?:, for example:
// if the expression `entries.lastOrNull()?.y` is null then return `0f`
// v
val lastY = entries.lastOrNull()?.y ?: 0f
for the expression in your code above, you can using safe-call ?.let/?.run to make your code more clearly, for example:
//val foo = if (entries.isEmpty()) 0f else entries.last().y + 100f else 100f
// if no Entry in List return `0F` ---v
val foo = entries.lastOrNull()?.run { y + 100 } ?: 0F
// ^--- otherwise make the last.y + 100

If I've managed to understand you correctly, this will do the job:
val foo = if (entries.isEmpty()) 0f else entries.lastOrNull()?.y ?: 0f + 100f

Related

Syntax errors in main function - SML/NJ [deleting DO VAL, deleting VAL ID, SEMICOLON ID, deleting SEMICOLON END SEMICOLON]

May someone highlight to me why I am getting the syntax errors for the main function, so that I can fix it. I am quite new to the language. Actually I was introduced to it through the assignment, so I am totally lost as to how to refactor it to avoid the syntax error:
val IDs = [410021001,410021002,410021003,410021004,410021005,410021006,410021007,410021008,410021009,410021010];
val Names = ["Alan","Bob","Carrie","David","Ethan","Frank","Gary","Helen","Igor","Jeff"]: string list;
val HW1 = [90.0,85.0,90.0,117.0,85.0,90.0,117.0,117.0,117.0,117.0] : real list;
val HW2 = [84.5,49.0,110.5,85.0,56.0,65.0,65.0,59.5,50.0,50.0] : real list;
val HW3 = [117.0,117.0,117.0,0.0,65.0,117.0,50.0,51.0,75.0,75.0] : real list;
val Midterm = [60.0,57.0,6.0,44.0,72.0,43.0,54.0,75.0,53.0,75.0] : real list;
val Final = [66.0,64.0,62.0,55.0,66.0,75.0,75.0,75.0,75.0,75.0] : real list;
fun score(HW1, HW2, HW3, Midterm, Final) =
round(HW1 * 0.1 + HW2 * 0.1 + HW3 * 0.1 + Midterm * 0.3 + Final * 0.4);
fun letterGrade(score) =
if score >= 90 then "A+"
else if score >= 85 then "A"
else if score >= 80 then "A-"
else if score >= 77 then "B+"
else if score >= 73 then "B"
else if score >= 70 then "B-"
else if score >= 67 then "C+"
else if score >= 63 then "C"
else if score >= 60 then "C-"
else if score >= 50 then "D"
else "E";
val i = 0
val max = length(IDs)
fun main() =
while i < max do
var ind_score = score(HW1[i], HW2[i], HW3[i], Midterm[i], Final[i])
var grade = letterGrade(ind_score)
print(IDs[i], " ", Names[i], " ", ind_score, " ", grade)
i = i + 1
end
end
This is the error I am producing after running my programme, which shows that my errors start at this function:
Terminal feedback
Part 1 - Straightforward corrections
I'll go from the simplest to the most complex. I'll also provide a more functional implementation in the end, without the while loop.
The construct var does not exist in ML. You probably meant val ind_score = ...
Array indexing is not done by array[i]. You need (as with everything else) a function to do that. The function happens to be List.nth. So, everywhere you have HW1[i], you should have List.nth(HW1, i).
Most language constructs expect a single expression, so you usually cannot simply string commands as we do in imperative languages. Thus, there are some constructs missing after the do in your while.
Variables in functional languages are usually immutable by default, so you have to indicate when you want something to be mutable. In your while, you want i to be mutable, so it has to be declared and used as such: val i = ref 0. When using the value, you have to use the syntax !i to get the 'current' value of the variable (essentially, de-referencing it).
The function call syntax in ML does not use (). When you call a function like score(a, b, c, d) what you are doing is creating a tuple (a, b, c, d) and passing it as a single argument to the function score. This is an important distinction because you are actually passing a tuple to your print function, which does not work because print expects a single argument of type string. By the way, the string concatenation operator is ^.
If you do all these changes, you'll get to the following definition of main. It is quite ugly but we will fix that soon:
val i = ref 0 (* Note that i's type is "int ref". Think about it as a pointer to an integer *)
val max = length(IDs)
fun main() =
while !i < max do (* Notice how annoying it is to always de-reference i and that the syntax to access a list element is not very convenient *)
let (* The 'let in end' block is the way to define values that will be used later *)
val ind_score = score(List.nth(HW1, !i), List.nth(HW2, !i), List.nth(HW3, !i), List.nth(Midterm, !i), List.nth(Final, !i))
val grade = letterGrade(ind_score)
in ( (* The parenthesis here allow stringing together a series of "imperative" operations *)
print(Int.toString(List.nth(IDs, !i)) ^ " " ^ List.nth(Names, !i) ^ " " ^ Int.toString(ind_score) ^ " " ^ grade ^ "\n");
i := !i + 1 (* Note the syntax := to re-define the value of i *)
)
end;
Part 2 - Making it more functional
Functional language programs are typically structured differently from imperative programs. A lot of small functions, pattern matching and recursion are typical. The code below is an example of how you could improve your main function (it is by no means "optimal" in terms of style though). A clear advantage of this implementation is that you do not even need to worry about the length of the lists. All you need to know is what to do when they are empty and when they are not.
(* First, define how to print the information of a single student.
Note that the function has several arguments, not a single argument that is a tuple *)
fun printStudent id name hw1 hw2 hw3 midterm final =
let
val ind_score = score (hw1, hw2, hw3, midterm, final)
val grade = letterGrade ind_score
in
print(Int.toString(id) ^ " " ^ name ^ " " ^ Int.toString(ind_score) ^ " " ^ grade ^ "\n")
end;
(* This uses pattern matching to disassemble the lists and print each element in order.
The first line matches an empty list on the first element (the others don't matter) and return (). Think of () as None in Python.
The second line disassemble each list in the first element and the rest of the list (first::rest), print the info about the student and recurse on the rest of the list.
*)
fun printAllStudents (nil, _, _, _, _, _, _) = ()
| printAllStudents (id::ids, name::names, hw1::hw1s, hw2::hw2s, hw3::hw3s, mid::midterms, final::finals) =
(printStudent id name hw1 hw2 hw3 mid final;
printAllStudents(ids, names, hw1s, hw2s, hw3s, midterms, finals));
printAllStudents(IDs, Names, HW1, HW2, HW3, Midterm, Final);
Note that it is a bit of a stretch to say that this implementation is more legible than the first one, even though it is slightly more generic. There is a way of improving it significantly though.
Part 3 - Using records
You may have noticed that there is a lot of repetition on the code above because we keep having to pass several lists and arguments. Also, if a new homework or test was added, several functions would have to be reworked. A way to avoid this is to use records, which work similarly to structs in C. The code below is a refactoring of the original code using a Student record. Note that, even though it has a slightly larger number of lines than your original code, it is (arguably) easier to understand and easier to update, if needed. The important part about records is that to access a field named field, you use an accessor function called #field:
(* Create a record type representing a student *)
type Student = {id:int, name:string, hw1:real, hw2:real, hw3:real, midterm:real, final:real};
(* Convenience function to construct a list of records from the individual lists of values *)
fun makeListStudents (nil, _, _, _, _, _, _) = nil (* if the input is empty, finish the list *)
| makeListStudents (id::ids, name::names, hw1::hw1s, hw2::hw2s, hw3::hw3s, mid::midterms, final::finals) = (* otherwise, add one record to the list and recurse *)
{id=id, name=name, hw1=hw1, hw2=hw2, hw3=hw3, midterm=mid, final=final} :: makeListStudents(ids, names, hw1s, hw2s, hw3s, midterms, finals);
val students = makeListStudents (IDs, Names, HW1, HW2, HW3, Midterm, Final);
fun score ({hw1, hw2, hw3, midterm, final, ...}: Student): int = (* Note the special patter matching syntax *)
round(hw1 * 0.1 + hw2 * 0.1 + hw3 * 0.1 + midterm * 0.3 + final * 0.4);
fun letterGrade (score) =
if score >= 90 then "A+"
else if score >= 85 then "A"
else if score >= 80 then "A-"
else if score >= 77 then "B+"
else if score >= 73 then "B"
else if score >= 70 then "B-"
else if score >= 67 then "C+"
else if score >= 63 then "C"
else if score >= 60 then "C-"
else if score >= 50 then "D"
else "E";
(* Note how this function became more legible *)
fun printStudent (st: Student) =
let
val ind_score = score(st)
val grade = letterGrade(ind_score)
in
print(Int.toString(#id(st)) ^ " " ^ #name(st) ^ " " ^ Int.toString(ind_score) ^ " " ^ grade ^ "\n")
end;
(* Note how, now that we have everything in a single list, we can use map *)
fun printAllStudents (students) = map printStudent students;
printAllStudents(students);

PineScript formulation of condition?

Say I have 3 conditions, and I want to perform some action if 2 of these conditions are fulfilled. With a few number of combinations, like 3, the solution could be something like:
c1=...
c2=...
c3=...
if (c1==true and c2==true) then
elseif (c1==true and c3==true) then
elseif (c2==true and c3==true) then
This is not very practical with, say, 100 conditions of which 90 should be fulfilled.
Is there a more compact way to implement this in PineScript?
If you represent the boolean true/false of your condition as 1/0 ints, you could count them to see how many are true.
The shortest way I can think of, is putting them in an array, and calculate the sum of that array.
//#version=5
indicator("My Script")
var int c0 = 1
var int c1 = 0
var int c2 = 1
var int c3 = 1
var int c4 = 1
var int c5 = 0
var int c6 = 0
var int c7 = 1
var int c8 = 1
var int c9 = 1
var int[] a = array.from(c0,c1,c2,c3,c4,c5,c6,c7,c8,c9)
mySum = array.sum(a)
plot(mySum)

Extract "Red" "Blue" "Circle" "Black" from "RedBlueCircleBlack" using capital as delimiter?

Is this a RegEx problem?
To note: there will always be only four items, each starts with a capital letter, each will be in order (color,color,shape,color):
"BlackWhiteTriangleGreen" etc.
So,
a="BlackWhiteTriangleGreen"
yields:
c1 = "Black"
c2 = "White"
S = "Triangle"
c3 = "Green"
EDIT: referencing the post suggested by Alex K., an AS3 solution as follows works:
private function UpperCaseArray(input:String):void {
var result:String = input.replace(/([A-Z]+)/g, ",$1").replace(/^,/, "");
var b:Array=result.split(",");
c1 = b[0];
c2 = b[1];
S = b[2];
c3 = b[3];
}
referencing the post suggested by Alex K., an AS3 solution as follows works:
private function UpperCaseArray(input:String):void {
var result:String = input.replace(/([A-Z]+)/g, ",$1").replace(/^,/, "");
var b:Array=result.split(",");
c1 = b[0];
c2 = b[1];
S = b[2];
c3 = b[3];
}

How can I get upper and lower limits in 1 line?

How can I get the min and max in one line?
d = {'k1': ['2000-01-01', '2003-01-01'],
'k2': ['2001-01-01', '2003-01-21'],
'k3': ['2001-11-01', '2002-01-01'],
}
d0 = min((a[0] for a in d.itervalues())) # '2000-01-01'
d1 = max((a[1] for a in d.itervalues())) # '2003-01-21'
Of course, the real dict is much longer than in this example. And of course too d0, d1 = min(...), max(...) is not the tricky I'm asking for :)
reduce(lambda lst, val: [min(lst[0],val[0]), max(lst[1],val[1])],iter(d.itervalues()))

Writing methods that call other methods inside d3 ember components?

Let's say I am creating a reusable component in Ember, and I want a helper function that calls another helper function defined within. For example,
App.SomeCoolComponent = Ember.Component.extend
offset: 50
position: (x) -> x * 100
offsetPosition: # would like (x) -> position(x) + offset
So conceptually, return a function that would evaluate the position at x, add offset, and return value. Obviously this is a silly example and I could just write offSetPosition without calling position, but in a more complex scenario that is repeating code. The problem is I can't figure out how to get this to work. I tried
offsetPosition: (x) -> #get('position')(x) + #get('offset')
which fails because #get isn't defined within the function, it has the wrong scope. I've tried to insert things like Ember.computed in various places also with no luck, e.g. the following also doesn't work:
offsetPosition: Ember.computed(->
(x) -> #get('position')(x) + #get('offset')).property('position', 'offset')
What is the correct way of doing this?
Ember version 1.3.0-beta.1+canary.48513b24. Thanks in advance!
Edit: seems like my problem stems from passing the function into a d3 call. For example:
App.SomeCoolComponent = Ember.Component.extend
offset: 50
position: (d, i) -> i * 100
offsetPosition: (d, i) ->
#position(d, i) + #get('offset')
# Some other code not shown
didInsertElement: ->
data = [1, 2, 3]
i = 1
d = data[i]
console.log(#position(d, i)) # works
console.log(#offsetPosition(d, i)) # works
d3.select('svg').selectAll('circle').data(data).enter().append('circle')
.attr('cx', #position) # works
.attr('cy', #offsetPosition) # fails
.attr('r', 30)
The error message is Uncaught TypeError: Object #<SVGCircleElement> has no method 'position'
Any thoughts on how to resolve this issue?
The problem is that you are passing a function offsetPosition (which references this and expects it to point to App.SomeCoolComponent) to a D3 callback where this is replaced by the DOMElement.
You can solve the problem in two ways:
Using the fat arrow syntax:
d3.select('svg').selectAll('circle').data(data).enter().append('circle')
.attr('cx', #position) # works
.attr('cy', (d, i) => #offsetPosition(d, i))
.attr('r', 30)
Using bind explicitly:
d3.select('svg').selectAll('circle').data(data).enter().append('circle')
.attr('cx', #position) # works
.attr('cy', #offsetPosition.bind(this))
.attr('r', 30)
methods (aka not computed properties) are in the current context and should just be called like a method, and not with getters/setters.
offsetPosition: (x) ->
#position(x) + #get("offset")
position: (x) ->
x * 100
Here's an example: http://emberjs.jsbin.com/eWIYICu/3/edit
App.AnAppleComponent = Ember.Component.extend({
offset: 50,
position: function(x) {
return x * 100;
},
offsetPosition: function(x) {
return this.position(x) + this.get('offset');
},
displayOffset: function(){
return this.offsetPosition(Math.floor(Math.random() * 10) + 1);
}.property('offset')
});
Personally I'd create a mixin and add my methods in there, then add the mixin wherever that logic is needed. Mixins are in the scope of whatever they are added to.
BTW You can use Ember.Get(object, 'propertyOnObject') anywhere in the app.
In response to your edit, you are passing in methods into those attribute values instead of the values of those methods (which is why it works above, but not below). There is a good chance since you are sending in those methods jquery is applying those methods later way out of scope.
didInsertElement: ->
data = [1, 2, 3]
i = 1
d = data[i]
position = #position(d, i)
offsetPosition = #offsetPosition(d, i)
console.log position
console.log offsetPosition
d3.select("svg").selectAll("circle").data(data).enter().append("circle").attr("cx", position).attr("cy", offsetPosition).attr "r", 30
I have a feeling you are wanting this to dynamically update or something along those lines, if that's the case you really want to be using computed properties, the bacon of Ember. Here's an updated version of the apple component:
http://emberjs.jsbin.com/eWIYICu/5/edit
<div {{bind-attr style='dynamicStyle'}}>
dynamicStyle: function(){
var rgb = this.get('rgb'),
rgb1 = rgb * 21 % 255,
rgb2 = rgb * 32 % 255,
rgb3 = rgb * 41 % 255;
return 'background-color:rgb(' + rgb1 + ',' + rgb2 + ',' + rgb3 + ');';
}.property('rgb'),