Fill a list with unique random values with F# - f#

I'm trying to learn F# but I'm stuck with a very simple thing.
I would like to create a list with uniques random values that I can display on a console. Let say Random from 1 to 100 and 10 elements in the list.
I've seen here this code F# getting a list of random numbers :
let genRandomNumbers count =
let rnd = System.Random()
List.init count (fun _ -> rnd.Next (1, 100))
let l = genRandomNumbers 10
printfn "%A" l
But how can I make theses numbers be differents ? This is not exactly a duplicate question because I don't find a way to be sure that each number is unique ; Random.Next can generate same numbers...

Here's a very simple solution:
let genRandomNumbers count =
let rnd = System.Random()
let initial = Seq.initInfinite (fun _ -> rnd.Next (1, 100))
initial
|> Seq.distinct
|> Seq.take(count)
|> Seq.toList
Note the Seq.distinct does exactly what you want to get the unique values. Also note that you'll get an issue if you try to get a count larger than 99 because there aren't that many distinct values between 1 and 99!

Related

Second Taxicab Number Generator

I am attempting to generate a series of guesses for the second Taxicab number. What I want to do is is call the Attempt function on a series of integers in a finite sequence. I have my two questions about implementation in the comments.
A taxi cab number, in case your wondering, is the least number that satisfied the sum of 2 unique cubes in for n unique sets of 2 unique cubes. Ta(2) is 1729.
[<EntryPoint>]
let main argv =
let Attempt (start : int) =
let stop = start+20
let integerList = [start..stop]
let list = List.init 3 (fun x -> integerList.[x])
//Is there a simple way to make initialize the list with random indices of integerList?
let Cube x = x*x*x
let newlist = list |> List.map (fun x -> Cube x)
let partitionList (x : List<int>) (y : int) = List.sum [x.[y];x.[y+1]]
let intLIST = [0..2]
let partitionList' = [for i in intLIST do yield partitionList newlist i]
let x = Set.ofList partitionList'
let y = Set.ofList partitionList'
//I was going to try to use some kind of equality operator to determine whether the two sets were equal, which could tell me whether we had actually found a Taxicab number by the weakened definition.
System.Console.Write(list)
System.Console.Write(newlist)
let rnd = System.Random()
//My primary question is how can I convert a random to an integer to use in start for the function Attempt?
System.Console.ReadKey() |> ignore
printfn("%A") argv
0
Dirty way to initialize list with random indexes of another list:
let randomIndexes count myList =
let rand = System.Random()
seq {
for n = 1 to count do
yield rand.Next(List.length myList) }
|> Seq.distinct
//|> Seq.sort // if you need them sorted
|> List.ofSeq
let result = randomIndexes 5 [3;2;4;5]
printfn "%A" result

F# Canopy - Generate Random Letters and or Numbers and use in a variable

I am using F# Canopy to complete some web testing. I am trying to create and load a random number with or without letters, not that important and use it to paste to my website.
The code I am currently using is
let genRandomNumbers count =
let rnd = System.Random()
List.init count
let l = genRandomNumbers 1
"#CompanyName" << l()
The #CompanyName is the ID of the element I am trying to pass l into. As it stands I am receiving the error 'The expression was expected to have type string but here it has type a list.
Any help would be greatly appreciated.
The << operator in canopy writes a string to the selector (I haven't used it but the documentation looks pretty clear), but your function returns a list. If you want the random string to work, you could do something like this (not tested code)
let randomNumString n = genRandomNumbers n |> List.map string |> List.reduce (+)
This maps your random list to strings then concats all the strings together using the first element as the accumulator seed. You could also do a fold
let randomNumString n = genRandomNumbers n
|> List.fold (fun acc i -> acc + (string i)) ""
Putting it all together
let rand = new System.Random()
let genRandomNumbers count = List.init count (fun _ -> rand.Next())
let randomNumString n = genRandomNumbers n |> List.map string |> List.reduce (+)
"#CompanyName" << (randomNumString 1)
In general, F# won't do any type promotion for you. Since the << operator wants a string on the right hand side, you need to map your list to a string somehow. That means iterating over each element, converting the number to a string, and adding all the elements together into one final string.

Sampling in F# : is Set adequate?

I have an array of items, from which I'd like to sample.
I was under the impression that a Set would the a good structure to sample from, in a fold where I'd give back the original or a modified set with the retrieved element missing depending if I want replacement of not.
However, there seems to no method to retrieve an element directly from a Set.
Is there something I am missing ? or should I use Set of indices, along with a surrogate function that starts at some random position < Set.count and goes up until it finds a member ?
That is, something along this line
module Seq =
let modulo (n:int) start =
let rec next i = seq { yield (i + 1)%n ; yield! next (i+1)}
next start
module Array =
let Sample (withReplacement:bool) seed (entries:'T array) =
let prng, indexes = new Random(seed), Set(Seq.init (entries |> Array.length) id)
Seq.unfold (fun set -> let N = set |> Set.count
let next = Seq.modulo N (prng.Next(N)) |> Seq.truncate N |> Seq.tryFind(fun i -> set |> Set.exists ((=) i))
if next.IsSome then
Some(entries.[next.Value], if withReplacement then set else Set.remove next.Value set)
else
None)
Edit : Tracking positively what I gave, instead of tracking what I still can give would make it simpler and more efficient.
For sampling without replacement, you could just permute the source seq and take however many elements you want to sample
let sampleWithoutReplacement n s =
let a = Array.ofSeq s
seq { for i = a.Length downto 1 do
let j = rnd.Next i
yield a.[j]
a.[j] <- a.[i - 1] }
|> Seq.take n
To sample with replacement, just pick a random element n times from the source seq
let sampleWithReplacement n s =
let a = Array.ofSeq s
Seq.init n (fun _ -> a.[rnd.Next(a.Length)])
These may not be the most efficient methods with huge data sets however
Continuing our comments...if you want to randomly sample a sequence without slurping the entire thing into memory you could generate a set of random indices the size of your desired sample (not too different from what you already have):
let rand count max =
System.Random()
|> Seq.unfold (fun r -> Some(r.Next(max), r))
|> Seq.distinct
|> Seq.take count
|> set
let takeSample sampleSize inputSize input =
let indices = rand sampleSize inputSize
input
|> Seq.mapi (fun idx x ->
if Set.contains idx indices then Some x else None)
|> Seq.choose id
let inputSize = 100000
let input = Seq.init inputSize id
let sample = takeSample 50 inputSize input
printfn "%A" (Seq.toList sample)

F# getting a list of random numbers

I am trying to fill a list with random numbers and am having diffculty getting the random number part. What I have right now prints out a random number 10 times, what I want is to print out 10 different random numbers
let a = (new System.Random()).Next(1, 1000)
let listOfSquares = [ for i in 1 .. 10->a]
printfn "%A" listOfSquares
any tips or suggestions?
Your code is simply getting one random number and using it ten times.
This extension method might be useful:
type System.Random with
/// Generates an infinite sequence of random numbers within the given range.
member this.GetValues(minValue, maxValue) =
Seq.initInfinite (fun _ -> this.Next(minValue, maxValue))
Then you can use it like this:
let r = System.Random()
let nums = r.GetValues(1, 1000) |> Seq.take 10
let genRandomNumbers count =
let rnd = System.Random()
List.init count (fun _ -> rnd.Next ())
let l = genRandomNumbers 10
printfn "%A" l
When I write a random something dispenser I like to use the same random number generator for each call to the dispenser. You can do that in F# with closures (a combination of Joel's and ildjarn's answer).
Example:
let randomWord =
let R = System.Random()
fun n -> System.String [|for _ in 1..n -> R.Next(26) + 97 |> char|]
In this way, a single instance of Random is 'baked into' the function, reusing it with each call.
There are two problems:
1) In F# functions are supposed to be pure so a function without arguments is considered as final value.
To declare impure function "without arguments", let it take one argument of type unit
let a () = (new System.Random()).Next(1, 1000)
and call it passing unit argument
let list = [ for i in 1 .. 10 -> a () ]
Source
2) New System.Random() instance is created each time when a is called. This results in getting same numbers. To fix this, create the instance only once
let random = new System.Random()
let a () = random.Next(1, 1000)
let list = [ for i in 1 .. 10 -> a ()]
This isn't specific to F#, read explanation for C# for better understanding
You could also avoid declaring an impure function as said by Pavel and just run:
let rnd = Random()
let rndList = [for i in 0..100 do rnd.Next(1000)]
I think one should be careful how to initialize System.Random as it uses the current time as seed. One instance should be enough for the whole app. Injecting random into functions has the advantage that you can use a fixed seed and reproduce with semi randomness, e.g. for testing your logic.
let rnd = System.Random()
let genRandomNumbers random count =
List.init count (fun _ -> random.Next ())
let getRandomNumbersSeeded = getRandomNumbers rnd
let l = getRandomNumbersSeeded 10
printfn "%A" l

F# How to Count Number of elements in a list that match some criteria?

I am prototyping how I am going to handle Double.NaN values in an F# array, and the first step, trying to simply count how many there are, has me stumped. The value "howMany" comes back as zero in my code, but I know there are 2, because I set 2 value to be Double.NaN. Can anyone point out what I am missing? Thanks!
let rnd = new System.Random()
let fakeAlphas = Array.init 10 (fun _ -> rnd.NextDouble());;
fakeAlphas.[0] <- Double.NaN;
fakeAlphas.[1] <- Double.NaN;
let countNA arr = arr |> Array.filter (fun x -> x = Double.NaN) |> Array.length;;
let howMany = countNA fakeAlphas;;
To answer the general question in the title:
let HowManySatisfy pred = Seq.filter pred >> Seq.length
for example
let nums = [1;2;3;4;5]
let countEvens = nums |> HowManySatisfy (fun n -> n%2=0)
printfn "%d" countEvens
Double.NaN = n is false for all n. See the MSDN page for Double.NaN.
Instead use Double.IsNaN. See the MSDN page for more information.
I think you need to use the Double.IsNan method. So your filter function would be:
(fun x -> Double.IsNan x)
I believe the issue is that NaN never equals anything -- even another NaN!

Resources