99 Problems in F# (1-10): 10 down, 89 to go

About a month ago, my brother and I started this site with the intention of going through Dr. Werner Hett's 99 Problems after being inspired by someone implementing them in Ruby. Since we were new to the language, we figured it would be a great way for us to gain a better understanding of the F# language; And it has been. Listed below are the first ten problems out of ninety-nine, so we still have a way to go. . . 

These may not be the "best" implementations of each solution; I'm sure these aren't the "best" solutions. Actually, if you have a better solution; I implore you to post it in the comments so I can edit the post for future viewers to observe your acuity. ;) 

(click the links for the problems to directed to more detailed posts. . . )
 

Problem #1: "Find the last element of a list" (detailed view)

    1 #light

    2 

    3 let myList =

    4      [1; 2; 3; 4]

    5      |> List.rev

    6      |> List.hd

    7      |> printf "Answer: %d" 

 

Problem #2: "Find the last but one element of a list" (detailed view)

    1 #light

    2 

    3 let listerine = [1 .. 40]

    4 let prob2 = List.nth listerine (List.length listerine - 2) |> printfn "Answer: %d"

 

Problem #3: "Find the K'th element of a list" (detailed view)

    1 #light

    2 

    3 let listerine k = [1 .. 40]  |> fun x -> List.nth x k

    4 

    5 printfn "Answer: %d" (listerine 27)

 

Problem #4: "Find the number of elements of a list" (detailed view)

    1 #light

    2 

    3 let listerine = [1 .. 40]  |> List.length |> printfn "List length: %d"

 

Problem #5: "Reverse a list" (detailed view) 

    1 #light
    2 
    3 let listerine = [1 .. 40] |> List.rev |> List.iter (printfn "%d"

 

Problem #6: "Find out whether a list is a palindrome" (detailed view)

let printListsEqual (listy : List<char>) =

     if listy.Equals(List.rev listy) then

          printfn "It's a palindrome!"

     else

          printfn "Not a palindrome!"

 

Problem #7: "Flatten a nested list structure" (recursively) (detailed view)

    1 #light

    2 

    3 let someList = [[1;2;3];[4;5];[6;7];[8]]

    4 let rec listFixer listy =

    5             if List.nonempty listy then

    6                 let top = listy |> List.hd

    7                 let tail = listy |> List.tl

    8                 top @ (listFixer tail)

    9             else

   10                 []

 

Problem #8: "Eliminate consecutive duplicates of list elements" (detailed view)

    1 #light

    2 

    3 let problem7 lister =

    4     let rec checker head tail =

    5         match tail with

    6         | h::t       -> if head = h then

    7                            checker h t

    8                         else

    9                            [head] @ checker h t

   10         | []        -> [head]          

   11     match lister with

   12     | h::t   -> checker h t

   13     | []    -> lister

   14 

   15 let megaList = [1;1;1;1;1;2;2;2;2;3;3;3;3;3;3;4;4;4;4;5;5;5;6;6;7;7;7

 

Problem #9: "Pack consecutive duplicates list elements into sublists" (detailed view)

    1 #light

    2 

    3 let oSnap = [1;1;1;2;2;2;2;2;2;3;3;3;3;3;3;4;]

    4 

    5 let prob9 listegosaurus =

    6     let rec packer listy tempy head tail =   

    7         match tail with

    8         | h::t -> if head = h then

    9                     packer listy (tempy @ [head]) h t

   10                   else

   11                     packer (listy @ [tempy @ [head]] ) [] h t

   12         | []   -> listy @ [[head]]

   13 

   14     match listegosaurus with

   15     | h::t   -> packer [] [] h t

   16     | []    -> [listegosaurus]

 

Problem #10: "Run-length encoding of a list" (detailed view)

    1 #light

    2 

    3 let oSnap = [1;1;1;2;2;2;2;2;2;3;3;3;3;3;3;4;]

    4 

    5 let prob10 listupendous =

    6     let rec packer listy tempy head tail =   

    7         match tail with

    8         | h::t -> if head = h then

    9                     packer listy (tempy @ [head]) h t

   10                   else

   11                     packer (listy @ [(List.length (tempy @ [head]), head)]) [] h t

   12         | []        -> listy @ [1 , head]

   13 

   14     match listupendous with

   15     | h::t   -> packer [] [] h t

   16     | []    -> [1, (listupendous |> List.hd)]

 That's it so far. If you have any implementations of any of the problems, please toss them in the comments and I'll be sure to put them in the body. 

kick it on DotNetKicks.com  


Currently rated 5.0 by 2 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories:

7 Comments
Actions: E-mail | Permalink | Comment RSSRSS comment feed

Problem #10

"Run-length encoding of a list."

And my solution: 

    1 #light

    2 

    3 let oSnap = [1;1;1;2;2;2;2;2;2;3;3;3;3;3;3;4;]

    4 

    5 let prob10 listupendous =

    6     let rec packer listy tempy head tail =   

    7         match tail with

    8         | h::t -> if head = h then

    9                     packer listy (tempy @ [head]) h t

   10                   else

   11                     packer (listy @ [(List.length (tempy @ [head]), head)]) [] h t

   12         | []        -> listy @ [1 , head]

   13 

   14     match listupendous with

   15     | h::t   -> packer [] [] h t

   16     | []    -> [1, (listupendous |> List.hd)]

  Like last time, it's a lot like my implementation of problem 8 and 9 with one difference. Instead of returning a list or a list of a list, we're returning a tuple with the count of how many of each element AND the value of the element. 

I'd like to thank Claudio Cherubino for his post on run length encoding which gave some great insight on the problem. 

 


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories:

0 Comments
Actions: E-mail | Permalink | Comment RSSRSS comment feed

Problem #9

"Pack consecutive duplicates of list elements into sublists."

My solution:

    1 #light

    2 

    3 let oSnap = [1;1;1;2;2;2;2;2;2;3;3;3;3;3;3;4;]

    4 

    5 let prob9 listegosaurus =

    6     let rec packer listy tempy head tail =   

    7         match tail with

    8         | h::t -> if head = h then

    9                     packer listy (tempy @ [head]) h t

   10                   else

   11                     packer (listy @ [tempy @ [head]] ) [] h t

   12         | []   -> listy @ [[head]]

   13 

   14     match listegosaurus with

   15     | h::t   -> packer [] [] h t

   16     | []    -> [listegosaurus]

 This one was a wee bit tougher than problem 8. The general layout isn't all too different from problem 8, but inside of packer is where things are actually happening, so I'll head over there.

When the packer function is first called, I tossed in two empty lists for listy and tempy, along with the head and tail of listegasaurus. I had to make these two lists because there was really no other way (that I could think of) for me to hang on to elements that were the same while still holding on to the final list. 

Once inside packer, we just have to pack like elements into a list separated from different elements. To do this, I made it so if the tail passed in isn't empty (noting that we're at the last element) we just have to figure out if the head we passed in is the same as the next value in the list (the head from the tail we passed in). If so, we're just going to append that element as a list (noted by being inside of [ ]'s) to tempy and go through packer again with the next value and the rest of the tail. 

When the values are finally different, we just append tempy as a list (with head appended, so we don't lose a value) to our final list, listy.

That's pretty much it. Again, if anyone else has other ways of doing this, feel free to post in the comments. 


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories:

2 Comments
Actions: E-mail | Permalink | Comment RSSRSS comment feed

Problem #8

"Eliminate consecutive duplicates of list elements."

My solution:

    1 #light

    2 

    3 let problem7 lister =

    4     let rec checker head tail =

    5         match tail with

    6         | h::t       -> if head = h then

    7                            checker h t

    8                         else

    9                            [head] @ checker h t

   10         | []        -> [head]          

   11     match lister with

   12     | h::t   -> checker h t

   13     | []    -> lister

   14 

   15 let megaList = [1;1;1;1;1;2;2;2;2;3;3;3;3;3;3;4;4;4;4;5;5;5;6;6;7;7;7

Alright. What this is going to do is take the ridiculously huge megaList and make it prettier. 

First off, the list that's passed into prob7 is matched with either 'being a list' (h::t // which is just matching the list against it's elements) OR being an empty list ([]).

If the passed-in tail (tail) is not empty, we're going to see if the head of the passed-in tail (h) is the same as the passed-in head (head).

If they're equal, we're going to run the checker with the head of the passed-in tail (h) and the tail of the passed-in tail (t) to check the next set of values. So we're just tossing out all of the values in the list that have the same value except the last one.

If they're not equal, we're appending the results of the checker function with the head of the passed-in tail (h) and the tail of the passed-in tail (t) to check the next set of values. 

And If the passed-in tail (tail) is empty ([]), we have to return the passed in head, to make sure we're getting a return value when the passed in list only contains one element. 

I'd just like to thank Jesus DeLaTorre's beautiful code that helped me ultimately understand the power of match statements for this solution and avoid some really ugly looking code. ;) 

kick it on DotNetKicks.com  


Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories: F#

9 Comments
Actions: E-mail | Permalink | Comment RSSRSS comment feed

Problem #7

Sorry for the delay, but here is problem #7!

"Flatten a nested list structure." (recursively)

 So we're just making a list full of lists into just one list with recursion.

    1 #light

    2 

    3 let someList = [[1;2;3];[4;5];[6;7];[8]]

    4 let rec listFixer listy =

    5             if List.nonempty listy then

    6                 let top = listy |> List.hd

    7                 let tail = listy |> List.tl

    8                 top @ (listFixer tail)

    9             else

   10                 []

This function just takes the tip of the list, sets it as the head of the list (top in the function) and passes the tail through the function again to sort it out. When the function finally reaches the end of the list, the function does nothing. Easy!

Something new to note here is the @ operator. This operator appends the head of the list to the rest of the list. 

This solution was very much inspired by Robert Pickering's book Foundations of F#, which had a very similar example problem when covering lists. Be sure to check it out if you haven't already.

kick it on DotNetKicks.com


Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories:

2 Comments
Actions: E-mail | Permalink | Comment RSSRSS comment feed

Problem #2

Hello all! My brother has recently made a couple of posts regarding the 99 problems. So now it's my turn.

"Find the last but one element of a list."


Alright, so we've already found the last element of a list, now to find the second-to-last element. . .

    1 #light

    2 

    3 let listerine = [1 .. 40]

    4 let prob2 = List.nth listerine (List.length listerine - 2) |> printfn "Answer: %d"

  Whew! 

As you can see, I went ahead and made listerine a good-old-fasioned list from 1 through 40. The prob2 is where the real interesting stuff happens. First, we're using the List.nth aggregate operator, which takes in 2 values (the list you're looking through and which position of the list you want back [0 being the first element]) and spits out an integer. The first element, as you can see, is listerine. The second element goes ahead and grabs the length (as an integer) and returns exactly the value that we want, which is 2 less than the length (39). SUCCESS: We've got a solution. But let's see if we can clean that up a bit . . .

That's something that my brother and I were thinking of a late last night. We both wanted to narrow it down to just one easy, beautiful line but weren't having much success. Anytime I tried passing listerine to the List.nth aggregate operator using the forward pipe (this guy: |> ), it would spit out gibberish because we needed two elements. After a little bit more thinking, my brother finally got it.

    1 #light

    2 

    3 let listerine = [1 .. 40]  |> fun x -> List.nth x ((List.length x) -2) |> printfn "%d"

  That's it! The forward pipe (this guy: |> ) kind-of applies the function order backwards, so we're pushing the values into the anonymous function. Once there, it goes through the logic just like before, except now it's done in one easy, beautiful line.

Alright! If anyone has a better, cleaner, beautiful-er implementation of problem #2, please go ahead and post it in the comments.

 EDIT: 

Greg M in the comments just posted an extremely elegant solution in the comments. His solution is:

    1 #light

    2 

    3 let listerine = [1; 2; 3; 4] |> fun x -> List.nth(List.rev x) 1

 When looking up the element in the list (List.nth) instead of dealing with List.length, Greg went ahead and reversed the list and pulled up element 1. Simple as that!

Thanks Greg!

kick it on DotNetKicks.com  

 


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories:

5 Comments
Actions: E-mail | Permalink | Comment RSSRSS comment feed