You're going on a trip with some students and it's up to you to keep track of how much money each Student has. A student is defined like this:
class Student
:
def __init__(self, name, fives, tens, twenties)
:
self.name = name
self.fives = fives
self.tens = tens
self.twenties = twenties
As you can tell, each Student has some fives, tens, and twenties. Your job is to return the name of the student with the most money. If every student has the same amount, then return "all"
.
Notes:
- Each student will have a unique name
- There will always be a clear winner: either one person has the most, or everyone has the same amount
- If there is only one student, then that student has the most money
This challenge comes from MrAppa on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!
Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!
Discussion
F#, also handles empty lists (returning
"none"
) or lists where several but not all students have the same max amount (returning their names comma separated):Tests:
Wow. Very good. I was nowhere near getting this. I need to spend some time working through your solution.
Thank you - it is very instructional. I really like how you show your tests as well. I haven't quite got my head around setting up tests in F# yet.
Let me try to help you a little bit:
Student
type andtotalAmount
function are clear.match
inrichest
directly matches onstudents.Length
(a property of theList
type) and handles the 0 and 1 special cases:Now the code that handles the general case looks like this, a typical functional pipeline:
In the first step, we group our list by the result of applying
totalAmount
to each list member. This could also be written slightly longer as:The result of this will be a list of tuples of the form
(totalValue, list of students with this value)
:Next we pick the tuple with the highest
totalValue
, which is the first tuple element and can be accessed byfst
(sligthly inefficient to do this in two steps, but the inputs are probably small enough to get away with and it's IMHO more readable). Once again this is the compact form of writing something like:We then pipe into
function
, which is essentially just a different way to do pattern matching. Roughly:The match cases use patterns on the tuple, but always ignore the first element (via
_
) and only focus on the list of students,l
. Alternatively we could have added another pipeline step to only pass through the second tuple element:The match case
(_, l) when l.Length = students.Length
matches only when the length ofl
is the same as the one ofstudents
, which means everyone has the same amount of money so we return"all"
. Otherwise we map over the list to extract the names (s.Name
) and join them with commas viaString.concat
. There's no checking of array length necessary here, in the case ofs.Length = 1
there's simply nothing to concat and a single string will be returned.My first attempt at F#
I couldn't get the syntax highlighting for F# so if anyone can point me in the right direction that would be much appreciated.
Generally we tend not to reach for classes in F# unless there's a good reason to do so, e.g. .NET interop or a problem that's really much better suited to OOP than FP. A record type and a simple function will do just fine here:
Thank you Michael. I have been following your F# posts in this series and found them very helpful.
I thought about using a record type but thought it would be easier to use a class property for the match function.
If you get chance please could you show how you would approach the full solution.
Many thanks.
Thanks, glad to hear that you find my posts useful. 😊
I posted a solution to this problem on this thread already, let me know if you have any questions.
renders as
(HEY, dev.to maintainers, this is one of those "won't fix bugs!" 😠 Why can't I nest backticks as in the github flavored markdown spec?)
Thank you
there is nothing more beautiful than Python
Usage:
Hi, check this decorator :
docs.python.org/3/library/functool...
Will make you avoid writing some functions.
Thank you Héctor i didn't know about this.
I've tried to apply it but it looks is a little shady for me, i didn't quite understand what is does and how it "magically" does the comparison
I put myself in here as a test case as a joke because I didn't get an allowance as a kid 😂
education.go
education_test.go
Javascript:
Usage:
Ridiculously over-engineered Kotlin version:
It's typesafe, and we could change the comparator out if we wanted to. A little kludgey in the fold section (I should probably involve Option to avoid people accidentally calling money on the
Empty
andError
types. 🤷♀️While I love the
sealed class
idea in Kotlin, type erasure and lack of true pattern matching really hampers the readability. If I was able to rely onStudentAccumulator
auto-casting to its internal types, then I could remove a when statement that just dispatches out to the same overloaded call with the proper type.Ok, I fixed it. It's not too much uglier with proper Option protection...
My try with python
In Scala -
Here is the Python code snippets:
My Python attempt :
Using total_ordering decorator from func_tools, which only requires two implementations of the comparison methods.