问题
I need to take a list of dates and a list of months and get a total count of the amount of dates that are in any of the months listed. Thus returning a single integer
I had a previously defined number_in_month
function which takes in a list of
dates and a single month and returns the amount of dates that fall in that
month. It has been tested and works correctly. I use this as the foundation for
the latter function. I've traced through the number_in_months
function many
times and I can't seem to find out whats wrong but it is simply not yielding the right answer
fun number_in_month (datelist : (int*int*int)list, month : int) =
let
fun count(x : int , datelist : (int*int*int)list)=
if null (tl datelist)
then x
else if #2(hd datelist) = month
then count(x+1, tl datelist)
else count(x, tl datelist)
in
if #2(hd datelist) = month
then count(1, datelist)
else count(0, datelist)
end
fun number_in_months (datelist : (int*int*int)list, monthlist : (int)list)=
let
fun count(x : int, monthlist : (int)list)=
if null (tl monthlist)
then x
else count((x + number_in_month(datelist, hd monthlist)), tl monthlist)
in
count (( number_in_month(datelist, hd monthlist), tl monthlist))
end
回答1:
As you have stated, you just have to use the previous function number_in_month
. Remembering that number_in_month
takes a list of dates and a single month, and returns the number of matching months in the list of dates. Thus All there is needed to create number_in_months
, is to call number_in_month
for each element in the new list of months, with the original list of dates to be checked.
Such a solution could look like
fun number_in_months (dates, months) =
if null months then
0
else
number_in_month(dates, hd months) + number_in_months(dates, tl months)
However when you use pattern matching, you can shorten it down and make it even more readable
fun number_in_months (dates, []) = 0
| number_in_months (dates, d::ds) =
number_in_month(dates, d) + number_in_months(dates, ds)
There is absolutely no reason for creating a count
function, carrying around a "state". This seems to be your imperative mind, at play :)
Take for example this simple function which will sum all element of a list
fun sum [] = 0
| sum (x::xs) = x + sum xs
or even creating a length function (which is actually similar to your count function)
fun length [] = 0
| length (x::xs) = 1 + length xs
Instead of repeating a lot of good stuff already mentioned so many times, I encouraging you to go read these questions and their answers.
Update
I also wanted to show you how to format you code in a better way
fun number_in_month (datelist : (int*int*int) list, month : int) =
let
fun count (x : int , datelist : (int*int*int) list) =
if null (tl datelist)
then x
else if #2(hd datelist) = month
then count (x+1, tl datelist)
else count (x, tl datelist)
in
if #2(hd datelist) = month
then count (1, datelist)
else count (0, datelist)
end
fun number_in_months (datelist : (int*int*int) list, monthlist : int list)=
let
fun count (x : int, monthlist : int list)=
if null (tl monthlist)
then x
else count (x + number_in_month(datelist, hd monthlist), tl monthlist)
in
count (number_in_month (datelist, hd monthlist), tl monthlist)
end
How to format nested if's is always a great debate where I'm from. Personally I avoid them, and use cases instead but I guess you will lean about that in the future.
However I also spotted a mistake in your count function. When you test whether your second argument (in both of your count functions) are the empty list with null
, you do it on the tail of the argument, which will fail if the argument is in fact the empty list
- null (tl []);
uncaught exception Empty
For example this imput
- number_in_months ([(1,1,1)], [1]);
uncaught exception Empty
Also your logic in number_in_month
is wrong, as you are testing for the head of the datelist
being equal to month
, however your to count
in either case uses the whole of datelist
instead of its tail. This is seen as the below should not return 2 as a result
- number_in_month([(1,1,1), (2,2,2), (3,3,3)], 1);
val it = 2 : int
This error, is the only thing that is making the number_in_month
function not throwing up an exception.
回答2:
The problem with your code is, you are not calculating the last date if it is matching with the month. this code works fine.
fun number_in_month (datelist : (int*int*int) list, month : int) =
let
fun count (x : int , datelist : (int*int*int) list) =
if null (tl datelist)
then
if #2(hd datelist) <> month
then x
else x+1
else if #2(hd datelist) = month
then count (x+1, tl datelist)
else count (x, tl datelist)
in
count (0, datelist)
end
来源:https://stackoverflow.com/questions/14470895/number-in-month-exercise-sml-list-iteration