up to oldest
This commit is contained in:
parent
a218605bfb
commit
79a441d61c
2 changed files with 276 additions and 11 deletions
|
@ -1,17 +1,41 @@
|
|||
(* year * month * day *)
|
||||
type Date = int * int * int
|
||||
|
||||
(*
|
||||
Pipe operator.
|
||||
Simply to write code like "data |> fun" instead "fun data".
|
||||
Then you can "pipe" results to functions via partial application:
|
||||
|
||||
fun square a b = a * b
|
||||
fun sum a b = a + b
|
||||
|
||||
10 |> sum 10 |> square 2 // 40
|
||||
*)
|
||||
fun |> (x, f) = f x
|
||||
|
||||
infix |>
|
||||
(* composition operator *)
|
||||
fun $ (f, x) = f x
|
||||
|
||||
fun fold f lst acc =
|
||||
case lst of
|
||||
[] => acc
|
||||
| head :: tail => fold f tail (f head acc)
|
||||
infix |>
|
||||
infix $
|
||||
|
||||
fun fold f acc lst =
|
||||
if lst = []
|
||||
then acc
|
||||
else
|
||||
let
|
||||
val tail = tl lst
|
||||
val head = hd lst
|
||||
in
|
||||
fold f (f head acc) tail
|
||||
end
|
||||
|
||||
fun reverse lst =
|
||||
fold (fn elm => fn acc => elm :: acc) lst []
|
||||
let
|
||||
fun f elm acc = elm :: acc
|
||||
in
|
||||
fold f [] lst
|
||||
end
|
||||
|
||||
|
||||
(* non tail optimized :( *)
|
||||
|
@ -25,18 +49,39 @@ fun reverse lst =
|
|||
|
||||
fun filter predicate lst =
|
||||
let
|
||||
val reversed = reverse lst
|
||||
fun f elm acc = if predicate elm then elm :: acc else acc
|
||||
in
|
||||
fold f reversed []
|
||||
lst |> fold f [] |> reverse
|
||||
end
|
||||
|
||||
fun range from to =
|
||||
let
|
||||
fun generate from to acc =
|
||||
if from > to
|
||||
then acc
|
||||
else generate (from + 1) to (from :: acc)
|
||||
in
|
||||
generate from to [] |> reverse
|
||||
end
|
||||
|
||||
(* naive sort, will blow up stack :( *)
|
||||
fun sort f lst =
|
||||
case lst of
|
||||
[] => []
|
||||
| hd :: [] => [hd]
|
||||
| first :: second :: rest =>
|
||||
if f first second
|
||||
then second :: first :: sort f rest
|
||||
else first :: second :: sort f rest
|
||||
|
||||
fun is_older ((y1, m1, d1): Date, (y2, m2, d2): Date): bool =
|
||||
let
|
||||
val same_dates = y1 = y2 andalso m1 = m2 andalso d1 = d2
|
||||
val older = y1 <= y2 andalso m1 <= m2 andalso d1 <= d2
|
||||
in
|
||||
if same_dates then false else older
|
||||
if same_dates
|
||||
then false
|
||||
else older
|
||||
end
|
||||
|
||||
fun number_in_month (dates: Date list, month_to_find: int): int =
|
||||
|
@ -46,7 +91,7 @@ fun number_in_month (dates: Date list, month_to_find: int): int =
|
|||
then occurences + 1
|
||||
else occurences
|
||||
in
|
||||
fold count_month dates 0
|
||||
fold count_month 0 dates
|
||||
end
|
||||
|
||||
fun number_in_months (dates: Date list, months_to_find: int list): int =
|
||||
|
@ -54,7 +99,7 @@ fun number_in_months (dates: Date list, months_to_find: int list): int =
|
|||
fun count_months month acc =
|
||||
acc + number_in_month (dates, month)
|
||||
in
|
||||
fold count_months months_to_find 0
|
||||
fold count_months 0 months_to_find
|
||||
end
|
||||
|
||||
fun dates_in_month (dates: Date list, in_month: int): Date list =
|
||||
|
@ -62,4 +107,88 @@ fun dates_in_month (dates: Date list, in_month: int): Date list =
|
|||
fun filter_dates (_, month, _) = in_month = month
|
||||
in
|
||||
filter filter_dates dates
|
||||
end
|
||||
|
||||
fun dates_in_months (dates: Date list, in_months: int list): Date list =
|
||||
let
|
||||
fun filter_dates month filtered =
|
||||
filtered @ dates_in_month (dates, month)
|
||||
in
|
||||
fold filter_dates [] in_months
|
||||
end
|
||||
|
||||
fun get_nth (strings: string list, nth: int): string =
|
||||
let
|
||||
fun find str (pos, found) =
|
||||
if pos = nth
|
||||
then (pos + 1, str)
|
||||
else (pos + 1, found)
|
||||
in
|
||||
fold find (1, "") strings |> #2
|
||||
end
|
||||
|
||||
(* this function will create list for months on every call :( *)
|
||||
fun date_to_string ((year, month, day): Date): string =
|
||||
let
|
||||
val months = [
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December"
|
||||
]
|
||||
|
||||
val string_month = get_nth (months, month - 1)
|
||||
|
||||
val to_str = Int.toString
|
||||
|
||||
fun pad num =
|
||||
if num < 10
|
||||
then "0" ^ to_str num
|
||||
else to_str num
|
||||
in
|
||||
string_month ^ " " ^ pad day ^ ", " ^ to_str year
|
||||
end
|
||||
|
||||
fun number_before_reaching_sum (sum: int, numbers: int list): int =
|
||||
if numbers = [] orelse hd numbers >= sum
|
||||
then 0
|
||||
else 1 + number_before_reaching_sum ((sum - hd numbers), tl numbers)
|
||||
|
||||
fun what_month (day: int): int =
|
||||
let
|
||||
val months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
||||
in
|
||||
number_before_reaching_sum (day, months) + 1
|
||||
end
|
||||
|
||||
(* correct but to complex for such problem *)
|
||||
(* fun month_range (day1: int, day2: int): int list =
|
||||
let
|
||||
fun append_month day months = what_month day :: months
|
||||
in
|
||||
range day1 day2 |> fold append_month [] |> reverse
|
||||
end
|
||||
*)
|
||||
|
||||
fun month_range (day1: int, day2: int): int list =
|
||||
if day1 > day2
|
||||
then []
|
||||
else what_month day1 :: month_range (day1 + 1, day2)
|
||||
|
||||
|
||||
fun oldest (dates: Date list): Date option =
|
||||
let
|
||||
fun compare a b = not $ is_older (a, b)
|
||||
in
|
||||
if dates = []
|
||||
then NONE
|
||||
else sort compare dates |> hd |> SOME
|
||||
end
|
|
@ -1,6 +1,19 @@
|
|||
use "test.sml";
|
||||
use "date.sml";
|
||||
|
||||
|
||||
val () =
|
||||
assert
|
||||
(range 1 2 = [1, 2])
|
||||
"range: generates sequence in right order"
|
||||
|
||||
val () = assert (sort (fn a => fn b => a > b) [] = []) "sort: empty list"
|
||||
val () = assert (sort (fn a => fn b => a > b) [1] = [1]) "sort: one val"
|
||||
val () =
|
||||
assert
|
||||
(sort (fn a => fn b => a > b) [2, 1] = [1, 2])
|
||||
"sort: two elements"
|
||||
|
||||
val () =
|
||||
assert
|
||||
(is_older ((1999, 12, 31), (1999, 12, 31)) = false)
|
||||
|
@ -119,4 +132,127 @@ val () =
|
|||
"dates_in_month: filter non matching dates"
|
||||
end
|
||||
|
||||
val () =
|
||||
let
|
||||
val dates = []
|
||||
val months = []
|
||||
val expect = []
|
||||
in
|
||||
assert
|
||||
(dates_in_months (dates, months) = expect)
|
||||
"dates_in_months: empty lists"
|
||||
end
|
||||
|
||||
val () =
|
||||
let
|
||||
val dates = [(2000, 11, 31), (2000, 12, 30), (2000, 12, 31)]
|
||||
val months = [11]
|
||||
val expect = [(2000, 11, 31)]
|
||||
in
|
||||
assert
|
||||
(dates_in_months (dates, months) = expect)
|
||||
"dates_in_months: match one date with one month"
|
||||
end
|
||||
|
||||
val () =
|
||||
let
|
||||
val dates = [(2000, 11, 31), (2000, 12, 30), (2000, 12, 31)]
|
||||
val months = [11, 12]
|
||||
val expect = dates
|
||||
in
|
||||
assert
|
||||
(dates_in_months (dates, months) = expect)
|
||||
"dates_in_months: match three dates with 2 months"
|
||||
end
|
||||
|
||||
val () =
|
||||
assert
|
||||
(get_nth (["first"], 1) = "first")
|
||||
"get_nth: get first element"
|
||||
|
||||
val () =
|
||||
assert
|
||||
(get_nth (["first", "second", "third"], 3) = "third")
|
||||
"get_nth: get third element"
|
||||
|
||||
val () =
|
||||
assert
|
||||
(get_nth (["first", "second", "third"], 4) = "")
|
||||
"get_nth: not found index returns empty string :)"
|
||||
|
||||
val () =
|
||||
assert
|
||||
(date_to_string ((2020, 06, 01)) = "May 01, 2020")
|
||||
"date_to_string: returns correct string"
|
||||
|
||||
val () =
|
||||
assert
|
||||
(number_before_reaching_sum (12, []) = 0)
|
||||
"number_before_reaching_sum: empty list returns zero"
|
||||
|
||||
val () =
|
||||
assert
|
||||
(number_before_reaching_sum (12, [1]) = 1)
|
||||
"number_before_reaching_sum: one list element"
|
||||
|
||||
val () =
|
||||
assert
|
||||
(number_before_reaching_sum (12, [4, 5, 1, 3]) = 3)
|
||||
"number_before_reaching_sum: list with overflowing sum"
|
||||
|
||||
val () =
|
||||
assert
|
||||
(number_before_reaching_sum (12, [12, 2]) = 0)
|
||||
("number_before_reaching_sum:" ^
|
||||
"first element already equals to sum but there is more")
|
||||
|
||||
val () =
|
||||
assert (what_month 365 = 12) "what_month: last day of a year"
|
||||
|
||||
val () =
|
||||
let
|
||||
val day1 = 1
|
||||
val day2 = 2
|
||||
val expect = [1, 1]
|
||||
in
|
||||
assert
|
||||
(month_range (day1, day2) = expect)
|
||||
"what_month: frist 2 days of a year"
|
||||
end
|
||||
|
||||
val () =
|
||||
let
|
||||
val day1 = 31
|
||||
val day2 = 33
|
||||
val expect = [1, 2, 2]
|
||||
in
|
||||
assert
|
||||
(month_range (day1, day2) = expect)
|
||||
"what_month: three days in two different months"
|
||||
end
|
||||
|
||||
val () =
|
||||
let
|
||||
val dates = []
|
||||
val expect = NONE
|
||||
in
|
||||
assert (oldest dates = expect) "oldest: retruns NONE on empty list"
|
||||
end
|
||||
|
||||
val () =
|
||||
let
|
||||
val dates = [(2000, 11, 31)]
|
||||
val expect = SOME (2000, 11, 31)
|
||||
in
|
||||
assert (oldest dates = expect) "oldest: retruns SOME date"
|
||||
end
|
||||
|
||||
val () =
|
||||
let
|
||||
val dates = [(2020, 11, 31), (2021, 11, 31)]
|
||||
val expect = SOME (2020, 11, 31)
|
||||
in
|
||||
assert (oldest dates = expect) "oldest: retruns oldest"
|
||||
end
|
||||
|
||||
val () = complete ()
|
Loading…
Reference in a new issue