Reputation: 242
Kata Description: The Western Suburbs Croquet Club has two categories of membership, Senior and Open. They would like your help with an application form that will tell prospective members which category they will be placed. To be a senior, a member must be at least 55 years old and have a handicap greater than 7. In this croquet club, handicaps range from -2 to +26; the better the player the lower the handicap. Input Input will consist of a list of lists containing two items each. Each list contains information for a single potential member. Information consists of an integer for the person's age and an integer for the person's handicap. Example Input
[[18, 20],[45, 2],[61, 12],[37, 6],[21, 21],[78, 9]]
Output Output will consist of a list of string values (in Haskell: Open or Senior) stating whether the respective member is to be placed in the senior or open category. Example Output
["Open", "Open", "Senior", "Open", "Open", "Senior"]
I have solved this Answer in three different languages: Python, C#, and finally JavaScript, my code is below. C#:
using System;
using System.Collections.Generic;
using System.Linq;
public class Kata
{
public static IEnumerable<string> OpenOrSenior(int[][] data) => data.Select(x => { return (x[0] >= 55 && x[1] > 7) ? "Senior" : "Open"; });
}
Python:
def openOrSenior(array): return [ "Senior" if (x[0] >= 55 and x[1] > 7) else "Open" for x in array]
JavaScript:
function openOrSenior(data) { return data.map(x => { if(x[0] >= 55 && x[1] > 7){return "Senior";}else{return "Open";} }); }
I'm having trouble though solving this problem in F#... I'm new to F#, I have Fuchu tests' already written out. I need some help on some changes I should make to my F# code if possible. F#: The function parameter needs to take a 2D array.
let OpenOrSenior _ =
let mutable _list : List<string> = []
let mutable _val : string = ""
for i in _ do
_val <- if i.[0] >= 55 && i.[1] > 7 then "Senior" else "Open"
_list <- _val :: _list
Please let me know what you think. Thanks in advance.
Upvotes: 1
Views: 3776
Reputation: 1
function openOrSenior(data){
return data.map(dig => (dig[0] >= 55 && dig[1] > 7 ? 'Senior' : 'Open'));
}
Upvotes: 0
Reputation: 147
" Categorize New Member "
JavaSvcript code using map and ternary operator.
function openOrSenior(data){
return data.map( x => x[0] >= 55 && x[1] > 7 ? "Senior" : "Open");
}
console.log(openOrSenior([[45, 12],[55,21],[19, -2],[104, 20]])); //,['Open', 'Senior', 'Open', 'Senior'])
console.log(openOrSenior([[3, 12],[55,1],[91, -2],[54, 23]])); //,['Open', 'Open', 'Open', 'Open'])
console.log(openOrSenior([[59, 12],[55,-1],[12, -2],[12, 12]])); //,['Senior', 'Open', 'Open', 'Open'])
Upvotes: 1
Reputation: 6324
As was suggested by the comments fsharpforfunandprofit, but also F# wiki and the MS docs are all great. For more open ended questions just drop by the F# Slack.
There are a couple of points, first, the domain would be much better modelled, by a list of tuples, or a record, then by a list of lists. Also Open or Senior should be modelled by a Discriminated Union. That way you could pattern match for most idiomatic and type safe code. However you can simply rewrite your function to take a list of lists, and map a function over it, just like you do in your other examples:
let ageAndHandi = [[18; 20];[45; 2];[61; 12];[37; 6];[21; 21];[78; 9]]
let openOrSenior (xs:List<List<int>>) =
xs
|> List.map
(fun (x:List<int>) -> if x.[0] >= 55 && x.[1] > 7 then "Senior" else "Open")
openOrSenior ageAndHandi //val it : string list = ["Open"; "Open"; "Senior"; "Open"; "Open"; "Senior"]
There are two ways to specify the type in F#, the .NET (List<List<int>>
) and ML int list list
. Either way is fine. However the preferred way is to avoid type annotations, let the type inference do its magic, and make the code as generic as possible. So you don't need to annotate the list at all.
As I said you can also do this with a for comprehension, which should be very readable even if you don't know F#:
let openOrSenior2 xs =
[for (x:List<int>) in xs do
if x.[0] >= 55 && x.[1] > 7 then yield "Senior" else yield "Open"]
openOrSenior2 ageAndHandi
And here is the version that actually models the domain, and uses pattern matching:
//record to describe a club member
type ClubMember = {
age: int
handi: int
}
//Discriminated Union to describe possible sub-types of club member
type MemberType = Open | Senior
//list of club members
let ageAndHandi2 = [{age=18;handi=20}
{age=45;handi=2}
{age=61;handi=12}]
//function to return the type of club member, notice that it's not a string
//but you could do that as well
let selectMember (mem:ClubMember) =
match mem with
| x when (mem.age >= 55) && (mem.handi > 7) -> Senior
| _ -> Open
//pipe the member list into the selection function, which return a MemberType List
ageAndHandi2
|> List.map selectMember
//val it : MemberType list = [Open; Open; Senior]
Upvotes: 2
Reputation: 2291
I tweaked your mutable version to get it working. The last line reverses the list to get the order right:
let openOrSenior (input:int list list) =
let mutable _list : List<string> = []
let mutable _val : string = ""
for i in input do
_val <- if i.[0] >= 55 && i.[1] > 7 then "Senior" else "Open"
_list <- _val :: _list
_list |> List.rev
However use of the mutable keyword is a sign of code smell. Here is a more functional version:
let openOrSenior =
List.map
(function
|age::[hcp] when age >= 55 && hcp > 7 -> "Senior"
|_ -> "Open")
Note: You need to replace , with ; in your input. Comma's are used for Tuple's in F#.
Upvotes: 2