List manipulation in F# - list

What I'm hoping to make this function do is:
Generate a list of random integers of length specified by count
Generate another random number to replace first element of list
Sort the list
Split list in half, discarding second half
Discard first element of list
Repeat 2-5 unless list is empty
What I have so far (but not working) is below. What is the matter with it?
let go count =
let rec cut l =
if List.length l = 0 then l
printfn "%A" l
let list = System.Random().Next(100)::List.tail l
let cut list =
let firstHalf= list |> Seq.take (List.length list / 2) |> Seq.toList
firstHalf
let listSorted = List.sort list
cut (List.tail listSorted)
let r = System.Random()
let list1 = List.init count (fun numbers -> r.Next(100))
printfn "List = %A" list1
cut list1

A few tips:
Don't test if a list is empty by List.length L = 0. Each test will take as long as the amount of elements in the list. Test with pattern matching instead, that's (almost) instantanteous:
Don't instantiate a new instance of a random number generator each time your cut function is called: let list = System.Random().... Doing that means that you're likely to get the same numbers (each instantiaion seeds the generator with the current system time). Just move your declaration r = System.Random() up a bit, and use that generator throughout your code.
example:
let rec cut l =
match l with
| [] -> // the list is empty, end the recursion here
| head::tail -> // the list consists of the head element and the rest
// you can refer to head and tail in your code here
let newlist = r.next(100) :: tail
You're declaring a function called 'cut' inside your recursive 'cut' function, which means that the last call to 'cut' in your recursive function actually calls the non-recursive one you defined inside. Use different names there.
You've written 'if List.length l = 0 then l', which (apart from not using a pattern match) also presents a problem: an 'if' in F# is an expression, like the ? operator in C#. In C# that would mean something like
(l.Count == 0) ? l : //other case missing! error! danger!
Another tip: once your list is sorted, you don't need to sort again each time you add a new random element. You can write code that inserts a new element in a sorted list that would be more efficient than adding an element and sorting afterwards. I'll leave the insert-into-sorted-list as an excercise.
I hope these tips are useful.

Here it is as simple as making functions for each of your statements.
let rnd = new System.Random()
let genList n =
[for i = 0 to n-1 do yield rnd.Next()]
let replaceHead v lst = match lst with
| [] -> []
| (x::xs) -> (v::xs)
let splitInHalf lst =
let len = (lst |> List.length) / 2
let rec loop n lst =
match (n,lst) with
| 0,_ -> []
| _,[] -> []
| _,(x::xs) -> x :: (loop (n-1) xs)
loop len lst
let start n =
let lst = genList n
let rec loop l =
match l with
| [] -> []
| ls -> match ls |> replaceHead (rnd.Next())
|> List.sort
|> splitInHalf with
| [] -> []
| xs -> xs |> List.tail |> loop
loop lst
start 1

here is my try...
let go count =
System.Random() |> fun rnd -> // With ranomizer ... (we will need it)
let rec repeat = function // So we got recursion
| x::xs when xs.Length <> 1 -> // while we have head and tail
printfn "%A" xs
rnd .Next(100) :: (List.tail xs) // Add random value
|> Seq.sort // Sort
|> Seq.take( abs(xs.Length /2) ) // Make a half
|> Seq.skip 1 // Remove first (just skip)
|> List.ofSeq // Make the list
|> repeat // So and repeat
| x::xs -> printfn "%A" xs
| _ -> () // If we have no head and tail
repeat <| List.init count (fun _ -> rnd.Next(100)) // do it with our random list

It does look like homework :)
But here is my take on it:
#light
// Create random integer sequence
let random_integers_of_length l =
(l, new System.Random())
|> Seq.unfold (fun (c, rnd) -> if c = 0 then None else Some (rnd.Next(), (c-1, rnd)))
|> Seq.cache
let rec mutate numbers =
printfn "%A" (List.ofSeq numbers); // pretty print the list
match numbers with
| _ when (Seq.length numbers) <= 1 -> printfn "Done.." // if length is 1 or 0 we can stop.
| _ ->
numbers
|> Seq.skip 1 // discard first element
|> Seq.append (random_integers_of_length 1) // append random number at the start
|> Seq.sort // sort
|> Seq.take ((Seq.length numbers) / 2) // take the first half, ignore the rest
|> Seq.skip 1 // discard first element
|> mutate // do it again.

Related

Outputting first n elements in the list

How do you write a f# recursive function that accepts a positive integer n and a list xs as input, and returns a list containing only the first n elements in xs.
let rec something n xs =
..
something 3 [1..10] = [1;2;3]
The short answer is: Don't, just use Seq.take.
A simple version would be something like:
let rec take n list =
match n with
| 0 -> []
| _ -> List.head list :: take (n - 1) (List.tail list)
A tail-recursive could look like:
let rec take n list =
let rec innertake m innerlist acc =
match m with
| 0 -> List.rev acc
| _ -> innertake (m - 1) (List.tail innerlist) ((List.head innerlist) :: acc)
innertake n list []
Note that neither of these does anything to handle the case that the input list is shorter than the requested number of items.

Removing consecutive duplicates from a list without recursion

I'm supposed to remove consecutive duplicates from an int list without using recursion and using only List.fold, map, filter, fold_left, fold_right.
I almost got it, but the problem with my code is that it checks if each element equals the 2nd element, and not the next element.
For example if let z = int list [3;1;4;5;5;1;1] my code will return [3;4;5] and not [3;1;4;5;1]. I'm not sure how to change it so filter uses a dynamically changing list parameter and not simply the original one (so it doesn't compare each element to the second element (1 in this case) each time):
let dupe (ls: int list) : int list =
List.filter (fun x -> if List.length ls = 0 then true else if x = List.hd (List.tl xs) then false else true) ls
The type of List.filter is this:
# List.filter;;
- : ('a -> bool) -> 'a list -> 'a list = <fun>
Notably, the filter function can see only one element of the list at a time. You need to see two consecutive elements to decide what to do, so I'd say List.filter won't do the job.
You're going to have to use map or one of the folds, I'd say. You can figure out which one(s) will work, with similar reasoning.
(I assume this is the sort of reasoning the assignment is supposed to illustrate. So I'm going to leave it there.)
Without rec
let remove = function
[] -> []
| x::tl ->
let (_,lxRes)=
List.fold_left (
fun (xPrec,lxRes) xCour ->
if xPrec=xCour then
(xCour,lxRes)
else
(xCour,lxRes#[xCour])
) (x+1,[]) (x::tl)
in
lxRes
Test:
# remove [3;1;4;5;5;1;1];;
- : int list = [3; 1; 4; 5; 1]
# remove [1;1];;
- : int list = [1]
# remove [1;1;1;1;2;2;3;4;5;5];;
- : int list = [1; 2; 3; 4; 5]
With rec (just for information)
let rec remove =
function
| [] -> []
| x::[] -> x::[]
| x::y::tl ->
if x=y then remove (y::tl)
else x::remove (y::tl)
Using just List.fold_left can be a little bit more concise than the previous answer. Of course, this will build up the list in reverse order, so we need to reverse the result.
let remove lst =
List.(
lst
|> fold_left
(fun acc x ->
match acc with
| [] -> [x]
| hd::_ when x = hd -> acc
| _ -> x::acc)
[]
|> rev
)
Of course, if you're not allowed to use List.rev we can reimplement it easily using List.fold_left, List.cons and Fun.flip.
let rev lst =
List.fold_left (Fun.flip List.cons) [] lst

Ocaml list of ints to list of int lists (Opposite of flattening)

With a list of integers such as:
[1;2;3;4;5;6;7;8;9]
How can I create a list of list of ints from the above, with all new lists the same specified length?
For example, I need to go from:
[1;2;3;4;5;6;7;8;9] to [[1;2;3];[4;5;6];[7;8;9]]
with the number to split being 3?
Thanks for your time.
So what you actually want is a function of type
val split : int list -> int -> int list list
that takes a list of integers and a sub-list-size. How about one that is even more general?
val split : 'a list -> int -> 'a list list
Here comes the implementation:
let split xs size =
let (_, r, rs) =
(* fold over the list, keeping track of how many elements are still
missing in the current list (csize), the current list (ys) and
the result list (zss) *)
List.fold_left (fun (csize, ys, zss) elt ->
(* if target size is 0, add the current list to the target list and
start a new empty current list of target-size size *)
if csize = 0 then (size - 1, [elt], zss # [ys])
(* otherwise decrement the target size and append the current element
elt to the current list ys *)
else (csize - 1, ys # [elt], zss))
(* start the accumulator with target-size=size, an empty current list and
an empty target-list *)
(size, [], []) xs
in
(* add the "left-overs" to the back of the target-list *)
rs # [r]
Please let me know if you get extra points for this! ;)
The code you give is a way to remove a given number of elements from the front of a list. One way to proceed might be to leave this function as it is (maybe clean it up a little) and use an outer function to process the whole list. For this to work easily, your function might also want to return the remainder of the list (so the outer function can easily tell what still needs to be segmented).
It seems, though, that you want to solve the problem with a single function. If so, the main thing I see that's missing is an accumulator for the pieces you've already snipped off. And you also can't quit when you reach your count, you have to remember the piece you just snipped off, and then process the rest of the list the same way.
If I were solving this myself, I'd try to generalize the problem so that the recursive call could help out in all cases. Something that might work is to allow the first piece to be shorter than the rest. That way you can write it as a single function, with no accumulators
(just recursive calls).
I would probably do it this way:
let split lst n =
let rec parti n acc xs =
match xs with
| [] -> (List.rev acc, [])
| _::_ when n = 0 -> (List.rev acc, xs)
| x::xs -> parti (pred n) (x::acc) xs
in let rec concat acc = function
| [] -> List.rev acc
| xs -> let (part, rest) = parti n [] xs in concat (part::acc) rest
in concat [] lst
Note that we are being lenient if n doesn't divide List.length lst evenly.
Example:
split [1;2;3;4;5] 2 gives [[1;2];[3;4];[5]]
Final note: the code is very verbose because the OCaml standard lib is very bare bones :/ With a different lib I'm sure this could be made much more concise.
let rec split n xs =
let rec take k xs ys = match k, xs with
| 0, _ -> List.rev ys :: split n xs
| _, [] -> if ys = [] then [] else [ys]
| _, x::xs' -> take (k - 1) xs' (x::ys)
in take n xs []

OCaml: swapping elements in a list

I'm wondering how can I write a function that divides a given list to sublists in a given point, swaps these sublists and returns a resulting list.
For example:
swap([1;3;5;6],2) => [5;6;1;3]
I suppose that the code that I developed is correct?
let rec swap (l,n) =
let rec loop t (count,laux) =
match t with
| h::t when count < n -> loop t (count+1, h::laux)
| h::t -> h::t# List.rev laux
| []->[]
in
loop l (0,[])
;;
You're almost there. The problem is your function handles the case when length of l is greater or equals to n incorrectly.
The pattern [] doesn't mean input list is empty; it means we come to the end of the list. What you should do at that point is returning the accumulator acc in the reverse order.
I rearrange patterns a little bit so base cases come first:
let rec swap (l, n) =
let rec loop xs count acc =
match xs with
| _ when count = n -> xs # List.rev acc
| [] -> List.rev acc
| h::t -> loop t (count+1) (h::acc)
in loop l 0 []

How do I increment a certain index of a list?

here's my code: (should work fine)
let rec interleave = function
| ([],ys) -> []
| (xs,[]) -> []
| (x::xs,y::ys) -> x :: y :: interleave (xs, ys)
let gencut n list =
let first = list |> Seq.take n |> Seq.toList
let last = list |> Seq.skip n |> Seq.toList
(first, last)
let cut list = gencut ((List.length list)/2) list
let shuffle x = interleave (cut x)
let isNotSame (list1, list2) = if list1 = list2 then false else true
let countShuffles xs =
let mutable newList = xs
let mutable x = 1
if (List.length(xs) > 1) then newList <- shuffle newList
while isNotSame (newList, xs) do
newList <- shuffle newList
x <- x + 1
x
//lists countShuffles from 1 to x
let listShuffles x =
for i = 1 to x/2 do
let y = [1..(i*2)]
let z = countShuffles y
printf "A deck of %d cards takes %d shuffles\n" (i*2) z
printf ""
The flow is (from main function down to 1st helper):
listShuffles -> countShuffles -> shuffle + isNotSame -> cut -> gencut + interleave
(so just try listShuffles)
What "countShuffles" does is:
take an int, creates a list, (1..n), (which is supposed to represent a deck of cards),
cuts it in half, does a perfect-out shuffle (perfect bridge shuffle)
and counts how many shuffles it takes to make the deck original again
What listShuffles does is:
takes an int, and prints out countShuffles 1 through n
(you need an even amount of cards in the deck)
Sorry about the explanation, now my question:
is it possible to see how many times a certain number is returned?
i.e.:
listShuffles 10000;;
see how many times "16" appeared.
i was thinking of making a list.
and incrementing a given index.
which represents a certain number that was returned.
but i cant find how to do that...
p.s. i dont care how my code is wrong or anything like that,
this is my first F# program, and it is homework based on my professor's criteria,
(the assignment is complete, this question is for curiosity)
There are a few alternatives
If you only want one number you can do
List |> Seq.sumBy (fun t -> if t = 16 then 1 else 0)
If you want a range of different numbers, it may be better to do
let map = List |> Seq.countBy (fun t -> t) |> Map.ofSeq
then map.[16] is the number of times that 16 occurs in the list
You can do something like:
let listShuffles x =
[| for i = 1 to x/2 do
yield countShuffles [1..(i*2)] |]
Now this function return array and then you can use Array module functions to find how many times a number appears
listShuffles 1000 |> Array.filter ((=) 16) |> Array.length
Or to print all such numbers and their occurrence count:
listShuffles 100
|> Array.toSeq |> Seq.groupBy id
|> Seq.iter (fun (k,v) -> printfn "%d appears %d times" k (v.Count()))