How to change for loop with an array module function? - arrays

This is a school assignment. I'm trying to make a function which takes an array A and makes a new array B, which is telling how many repeated numbers there are in an array. For example A is this:
A = [|2;9;9;2;2;4|]
The B would be:
B = [|3;2;2;3;3;1|]
Ny code is right now like this and working perfectly:
let A = [|2;9;9;2;2;4|]
let n = A.Length - 1
let B = Array.create A.Length 0
for i = 0 to n do
Array.iter (fun j -> if i <> j && A.[i]=j then B.[i] <- (B.[i] + 1)) A
printfn "%A" B
My question is, how much would asymptotic time be? I know the first for loop is O(n), but what about Array.iter? And is there any way to switch the first for loop with an array function?

Array.iter is linear in the array length, so your for loop is essentially O(n²) in time complexity. Replacing the loop with another Array.iter is possible but would not change the time complexity.
If you can solve the problem whichever way you want, I suggest using a Map to aggregate the numbers and their frequencies, then mapping the original array into one showing these frequencies. Since this is a school assignment, you should probably wait until after your submission deadline before you look at the following code:
let numFrequency (a : _ []) =
let m =
(Map.empty, a)
||> Array.fold (fun m n ->
Map.tryFind n m
|> Option.defaultValue 0
|> fun x -> Map.add n (x + 1) m)
Array.map (fun n -> Map.find n m) a
let A = [|2; 9; 9; 2; 2; 4|]
let B = numFrequency A
printf "%A\n%A\n" A B

Related

Randomized For...in loop

I was checking Microsoft f# guide on for...in loops and was wondering how could the for in loop be randomized.
For example:
let list1 = [ 1; 5; 100; 450; 788 ]
for i in list1 do
printfn "%d" i
output:
1
5
100
450
788
If I want to have the elements to be printed in a random order using for in loop, what could I do?
We have established that, essentially, there's only the Fisher–Yates shuffle for randomizing a given collection. Easy to get wrong; here's a C# discussion of Dos and Don'ts.
The freedoms we have left in implementation: we can count upwards or downwards when performing the random swaps, and we may decide to either mutate the array in place, or create a copy of the input data.
// Mutate in place, count downwards
let shuffle arr =
let rnd = System.Random()
for i in Array.length arr - 1 .. -1 .. 1 do
let tmp, j = arr.[i], rnd.Next(0, i)
arr.[i] <- arr.[j]; arr.[j] <- tmp
let a = [|1; 5; 100; 450; 788|]
shuffle a
// Create a copy, count upwards
let copyShuffle source =
let arr = Seq.toArray source
let rnd, len = System.Random(), arr.Length
for i in 0 .. len - 2 do
let tmp, j = arr.[i], rnd.Next(i, len)
arr.[i] <- arr.[j]; arr.[j] <- tmp
arr
copyShuffle [1; 5; 100; 450; 788]
|> Array.iter (printfn "%i")
Here is an easy way to do it using the random function
let random= new Random()
let randomizeList lst =
lst
|> List.sortBy (fun (_) -> random.Next(lst.Length * 1000))
let list1 = [ 1; 5; 100; 450; 788 ]
|> randomizeList
for i in list1 do
printfn "%d" i
Please see notes on the Random number generator with regards to randomness - there are better algorithms for producing a more pure random distribution, Dotnet Core Docs -
The chosen numbers are not completely random because a mathematical algorithm is used to select them, but they are sufficiently random for practical purposes.

How can I convert a 2D array to 1D functionally, in F#?

I can do it easily if I use a mutable counter and 2 for loops but I want to do it inside the Array.init function.
This is it so far, I just need to change the zeroes in array2D.[0, 0].
let array2D = Array2D.init 10 10 (fun i j -> 0)
let array = Array.init 100 (fun i -> array2D.[0, 0])
You are quite correct that you can use the combination of / and % to do this, such as:
// assume a 2d array array2d
let m = Array2D.length1 array2d
let n = Array2D.length2 array2d
let array1d = Array.init (m * n) (fun i -> array2d.[i / n, i % n]
That would be 'purely functional'. Heavy use of division, and especially modulus, however, is not likely to be especially performant. If performance is a concern, you would indeed be much better off doing something like:
// assume a 2d array array2d
let m = Array2D.length1 array2d
let n = Array2D.length2 array2d
let array1d = Array.zeroCreate (m * n)
for i = 0 to (m - 1) do
for j = 0 to (n - 1) do
array1d.[(i * n) + j)] <- array2d.[i,j]
F# is functional-first, not zealously-functional-only. It's fine to use an imperative style when performance is a major concern. That's why it's an option. Probably best to turn the above into a referentially-transparent function, such as make1darrayfrom2darray:
let make1darrayfrom2darray array2d =
let m = Array2D.length1 array2d
let n = Array2D.length2 array2d
let array1d = Array.zeroCreate (m * n)
for i = 0 to (m - 1) do
for j = 0 to (n - 1) do
array1d.[(i * n) + j] <- array2d.[i,j]
array1d
If you are doing this a heck of a lot but your arrays are not long-lived (and especially if you need large arrays), consider using the ArrayPool system. This will help your program avoid a lot of potentially expensive but unnecessary memory allocations.
I thought about it some more, and got it right. Sorry for the quick post, should have just spent a bit more time on it.
array2D.[i / 10, i % 10]

F# why arrays are not scrambled in a different way when mapping a function to scramble each array in an array

I wrote a function to scramble an array and map an array of arrays to scramble each one different but they are scrambled the same way
let rand = System.Random()
let shuffle (rand : System.Random)(array :int[] ) = let rng = new Random()
let mutable n = array.Length
while (n > 1) do
let k = rng.Next(n)
n <- n - 1
let temp = array.[n]
array.[n] <- array.[k]
array.[k] <- temp
array
let playsarray = shuffle rand
let scrambledarray = Array.map (fun x -> playsarray x )
let playsarra = fun (array : int[]) -> array |> playsarray
let smallarray = [1..10].ToArray()
let megaarray = Array.create 10 smallarray
let megarrayscrambled = megaarray |> scrambledarray
megarrayscrambled |> Seq.iter (fun y -> printfn "Ar: %A" y)
after running the code all the 10 arrays have the same order in the data ej
Ar: [|5; 1; 7; 2; 8; 10; 6; 3; 9; 4|]
Ar: [|5; 1; 7; 2; 8; 10; 6; 3; 9; 4|] and so on ...
There are two problems with your code.
First, your shuffle function takes a rand parameter but isn't actually using it: inside the function you create a new System.Random instance and use it instead of using the one passed in. The docs for the System.Random constructor mention (in the examples) that the default constructor uses the current time as a seed, so if two Random objects are created in quick succession, they would have the same seed and thus produce the same values. To fix this problem, you just need to stop creating a new Random instance in your shuffle function and instead use the one passed in (I renamed it from rand to rng so that the rest of your code wouldn't need changing). Here's your shuffle function with that change made (and with much easier-to-read indentation: you don't have to start the first line of the function on the same line as the = sign; you can put it on the next line and just indent one indentation level, four spaces):
let shuffle (rng : System.Random) (array : int[]) =
let mutable n = array.Length // The number of items left to shuffle (loop invariant).
while (n > 1) do
let k = rng.Next(n) // 0 <= k < n.
n <- n - 1 // n is now the last pertinent index;
let temp = array.[n] // swap array[n] with array[k] (does nothing if k == n).
array.[n] <- array.[k]
array.[k] <- temp
array
BUT that won't solve your issues just yet, because you've also misunderstood how Array.create works. It creates an array of a given size, where each item in the array contains the value you passed in. I.e., every entry in your megarrayscrambled array contains a reference to the same smallarray. If you did megarrayscrambled.[0].[0] <- 999 you'd see that this changed every one of the ten entries in megarrayscrambled, because they're the same array.
What you actually wanted was to use Array.init, not Array.create. Array.init takes a function and runs that function once per item it's creating in the array you're building. This means that if that function returns [1..10].ToArray(), then each time it's called it will return a different array, and you'll therefore get the results you expect. (By the way, you can create an array more simply by doing [|1..10|], and that's what I'll use in the sample code below).
So just change your let megaarray line to:
let megaarray = Array.init 10 (fun _ -> [|1..10|])
and then you should see the results you were expecting.
BTW, one more little detail: in one line you have Array.map (fun x -> playsarray x), but that is just equivalent to Array.map playsarray, which is a little simpler to read.

Standard ML running multiple functions in a loop (Using recursion or any other means)

I have defined three different functions that will perform calculations and return a value. These functions will consistently be redefining a variable until a specific condition is reached. I am having issues getting these to run in a "loop" scenario. I know functional languages are not best for performing loops and you should use recursion...but I am having a hard time wrapping my head around how to perform this.
I will make some real simple arbitrary functions to explain my situation.
fun add_them (a,b) =
a+b;
fun substract_them (c,d) =
c-d;
fun add_them2 (e,f) =
e-f;
val a = 5;
val b = 7;
val c = 10;
val d = 1;
val a = add_them (a,b);
val d = add_them2 (c,d);
So let's say I want to run the last two lines a 1000 times. So Val A and Val D will keep getting added up to a huge number. Now I could literally copy and paste those two lines a 1000 times and get the result I want..but this of course defeats the purpose of programming :)
I was trying to create a loop that I can throw these two functions in. I was coming up with something like below, but I would have no idea how to incorporate these two. Perhaps I am going at this completely backwards.
fun whileloop (x,a) =
if (a<1)
then x
else whileloop(x+1,a-1);
So my goal was to insert those above val a and val d expressions into another function using recursion and run it a certain amount of times. Any help would be much appreciated.
A function that simply iterates another function n times is given in my answer here. But it sounds like you want to apply a given function n times to a seed, like so:
f (f (f (f ... (f x) ... )))
That can be accomplished by the following function:
fun repeat n f x = if n = 0 then x else repeat (n-1) f (f x)
For example,
val n = repeat 20 (fn => n + 1) 0
results in 20.
Or perhaps you want to repeat based on a condition instead of a count:
fun repeatWhile p f x = if p x then repeatWhile p f (f x) else x
For example,
val n = repeatWhile (fn x => x > 0) (fn x => x - 1) 20
returns 0.
Both functions are polymorphic, so also work with tuples. For example:
val (x, y) = repeatWhile (fn (a, b) => a > 0) (fn (a, b) => (a-1, b+1)) (20, 0)
returns (0, 20).
If you dislike using two separate function parameters for condition and "action", you can also combine them by having it return a pair:
fun repeatWhile2 f x =
let val (c, y) = f x in if c then repeatWhile2 f y else x end
Then:
repeatWhile (fn (a, b) => (a > 0, (a-1, b+2))) (20, 0)

F# Sum of products of an array with element position

Coming of a C# background and trying to learn F#.
I'm trying to iterate over an array of size 256, so the total sum of it be the product of the element position and the element, like this:
float sum = 0.0;
for (int i = 0; i < 256; i++) {
sum += i * arr[i];
}
I made this but I don't know if this is the best way to do it in F#, probably not.
let mutable sum = 0
for i in 0 .. 255 do
sum <- sum + i * arr.[i]
done
I don't know if it's possible to use Array.fold or Array.iteri to solve this in a better way.
You can use mapi and sum:
let f s = s |> Seq.mapi (fun i j -> i * j) |> Seq.sum
One way of doing this with only one iteration through the array:
let f s = snd (Array.fold (fun (i, sum) x -> (i + 1, sum + x * float i)) (0, 0.0) s)
Although I prefer Lee's solution as being much easier to follow.
An alternative would be to write your own Array.foldi function and use that.

Resources