I need to add 1 to each element in an array, and if it goes out of range, I need to start over.
let arr = [| 1; 2; 3 |]
for i = 0 to Array.length arr - 1 do
arr.[i] <- arr.[i] + 1
printfn "i %A" (arr.[i])
I want to add 5 points to the array, so that it iterates over the array and gives one point in each element, so the array would partially be [| 2; 3; 4 |] and iterate through the array again and end up being arr = [| 3; 4; 4 |]
Actually you can calculate exactly how much you should add to each element of array. So you can solve the problem by going through the array in only one time.
let addPoints arr points =
let len = arr |> Array.length
let added = points / len
let extraCount = points % len
arr
|> Array.mapi (fun i x ->
if i < extraCount then x + added + 1
else x + added)
addPoints [| 1; 2; 3 |] 5
|> printfn "%A" // [|3; 4; 4|]
Mutating the array or not, it's up to you.
Rather than mutating the array, a more idiomatic F# approach is to create a new array with the newly calculated results. You can use the built-in Array.map function to do apply the same transformation to each element of the array. To increment all by one, you can write:
let arr = [| 1; 2; 3 |]
arr |> Array.map (fun v -> v + 1)
If you want to restrict the maximal value to 4, you'll need to do that in the body of the function, i.e. v + 1. To make it easier to do this repeatedly, it's helpful to define a function.
let step arr =
arr |> Array.map (fun v -> min 4 (v + 1))
Here, step is a function you can call to do one step of the transformation. min 4 (v + 1) ensures that when v + 1 is more than 4, you get just 4 as the result. Now you can run step repeatedly using |>:
let arr1 = arr |> step
let arr2 = arr |> step |> step
I agree with #TomasPetricek in that the way to go should be to create new arrays using map. However, if you must mutate the array, the following loop-based approach should work just fine:
let incArrayElements n (a : _ []) =
let rec loop k i =
if k > 0 then
a.[i] <- a.[i] + 1
let ii = i + 1
if ii >= a.Length then 0 else ii
|> loop (k - 1)
if n > 0 then loop n 0
If required, this can also be easily modified to include a parameter for the starting index.
Related
Lets say I have an the following Array2D
> let arr = Array2D.init 2 3 (fun i j -> (i+1) * (j+2));;
> printfn "%A" arr
[[2; 3; 4]
[4; 6; 8]]
I know I can access an array element like so
> arr[1, 2];;
8
But what if I have the coordinates saved in a tuple. Why can't I do the following or something similar:
> let coord = (1, 2);;
> arr[coord]
Error: input.fsx (2,1)-(2,11) typecheck error This expression was expected to have type
''a[]'
but here has type
'int[,]'
It feels kinda stupid to unpack the tuple each time before using it. Or is this the only way?
> let x, y = coord;;
> arr[x, y];;
8
You could always use ||> to unpack the tuple rather than using let expressions, along with Array2D.get. The downside is that its a lil more verbose for sure.
- let arr = Array2D.init 2 3 (fun i j -> (i+1) * (j+2))
- let coord = (1,2)
- coord ||> Array2D.get arr;;
val it : int = 8
I don't think there's any direct way to index a 2D array using a tuple. One similar alternative is to use a Map instead:
let map =
seq {
for i = 0 to 1 do
for j = 0 to 2 do
yield (i, j), (i+1) * (j+2)
} |> Map
let coord = (1, 2)
map[coord] // 8
F# treats tupled arguments in a special way. If method is defined not in F#, then it's arguments should be tupled:
System.String.Join(", ", [|1; 2; 3|])
System.String.Join ", " [|1; 2; 3|] // not valid
It's done to help overload resolution.
What you can do is to extend multidimensional array type:
type ``[,]``<'a> with
member inline ar.Item with get ((x, y): (int*int)) : 'a =
ar.[x, y]
And then use it:
let coord = (1, 2)
arr.Item coord |> printfn "%d"
Unfortunately arr.[coord] is not available and looks like a bug in compiler
All problems are solved through functions!
let xss = Array2D.init 2 3 (fun i j -> (i+1) * (j+2));;
let get arr (x,y) = Array2D.get arr x y
get xss (1,2) (* Returns 8 *)
How do you flatten a 2d array to a 1d array by appending each row to the one above?
My problem is not understanding how to use map to do this as other functional languages have a flatmap/(insert similar name here) function to do this.
let colors = Array2D.init 800 480 (fun i j ->
if i % 3 = 0 || j % 3 = 0 then Color.Black
else Color.Red)
let data = colors |> map (fun c -> c)
How woulds I use map such that the return type from the map is changed to a 1d array?
for Sequences use Seq.fold + Seq.append + empty Seq
let seq2d = seq {yield seq{1..3}; yield seq{4..6} }
seq2d |> Seq.fold Seq.append Seq.empty<int>
//[1; 2; 3; 4; 5; 6;]
or even less typing with just Seq.reduce + Seq.append
seq2d |> Seq.reduce Seq.append
//[1; 2; 3; 4; 5; 6;]
for lists (but not Sequences) it's List.reduce + List.append
let list2d = [ [1;2;3]; [4;5] ]
list2d |> List.reduce List.append
//[1; 2; 3; 4; 5]
If you just want to flatten it you can cast it to a seq:
colors |> Seq.cast<Color>
|> Seq.length //val it : int = 384000
There might be something in Array2D that's more convenient but Array2D is really a .NET collection. You can work with ragged arrays or lists and then you can have access to Seq.concat or collect.
Add1
Here it is already in a 1D List:
let colors = [for i in 0..799 do
for j in 0..479 ->
if (i % 3 = 0) || (j % 3 = 0) then Color.Black
else Color.Red]
With Active Patterns
Depending on the actual complexity this might also be a good candidate for active patterns. Below an active recognizer for Black and Red is defined, together with the pattern matching, then the 2D List is generated which is fed to concat, and finally checked against the original Array2D. You don't need to work with Lists of course (e.g. can be seq for laziness or Array for performance).
let (|Black|Red|) input = if fst input % 3 = 0 || snd input % 3 = 0 then Black else Red
let matchColor =
function
|Black -> Color.Black
|Red -> Color.Red
let color3 = List.init 800 (fun i -> List.init 480 (fun j -> matchColor (i,j)))
let color4 = color3 |> List.concat
color4 |> Seq.length
colors
|> Array2D.mapi (fun i j x -> color3.[i].[j] = colors.[i,j])
|> Seq.cast<bool>
|> Seq.filter not
Suppose we have a pair of input arrays, or a list of (key, value) tuples if you prefer. What's an elegant and performant way to combine values that have indices falling in a certain interval? For example, if the interval (or 'bin') size is 10 then the values of all indices from 0 < x <= 10 would be combined, as would the values of indices from 10 < x <= 20 and so on. I want:
let interval = 10
let index = [| 6; 12; 18; 24 |]
let value = [| a; b; c; d |]
result = [| a; b + c; d |]
The crudest way to do this would be to use a whole lot of if, else if statements (the index range has a defined upper limit). I got close with
for i = 0 to index.Length do
result.[Math.Floor(index.[i]/10] += value.[Math.Floor(index.[i]/10]
but this is doing 0 <= x < 10, not 0 < x <= 10.
I also tried assuming the indices are ordered and evenly spaced, with
for i = 1 : ( index.Length - 1 ) / valuesPerBin
valueRange = ((i-1)*valuesPerBin + 1) : i*valuesPerBin )
result(i) = sum(value(valueRange))
which is nice but obviously breaks if there is a non integer number of values per bin.
What's the best way of doing this in F#? Is there a name or an existing function for what I'm trying to do?
let interval = 10
let index = [6;12;18;24]
let value =[101;102;103;104]
let intervals = List.map (fun e -> e/interval) index
let keys = List.map2(fun e1 e2 -> (e1,e2)) intervals value
let skeys = Seq.ofList keys
let result = skeys
|>Seq.groupBy (fun p -> fst p)
|>Seq.map (fun p -> snd p)
|>Seq.map(fun s -> Seq.sumBy (fun p -> snd p) s)
result will be [101;205;104] (as a Seq).
If you want to convert to an array, apply Seq.toArray.
Is it what you wanted ?
Adapt the surrounding code to use
0 <= x < 10 instead of 0 < x <= 10. In my case this was just a simple definition change in another function, allowing me to use
for i = 0 to index.Length do
result.[Math.Floor(index.[i]/10] += value.[Math.Floor(index.[i]/10], which is much simpler and terser syntax than the alternatives.
I want to solve this excercise: http://code.google.com/codejam/contest/351101/dashboard#s=p0 using F#.
I am new to functional programming and F# but I like the concept and the language a lot. And I love the codejam excercise too it looks so easy but real life. Could somebody point me out a solution?
At the moment I have written this code which is just plain imperative and looks ugly from the functional perspective:
(*
C - Credit
L - Items
I - List of Integer, wher P is single integer
How does the data look like inside file
N
[...
* Money
* Items in store
...]
*)
let lines = System.IO.File.ReadAllLines("../../../../data/A-small-practice.in")
let CBounds c = c >= 5 && c <= 1000
let PBounds p = p >= 1 && p <= 1000
let entries = int(lines.[0]) - 1
let mutable index = 1 (* First index is how many entries*)
let mutable case = 1
for i = 0 to entries do
let index = (i*3) + 1
let C = int(lines.[index])
let L = int(lines.[index+1])
let I = lines.[index+2]
let items = I.Split([|' '|]) |> Array.map int
// C must be the sum of some items
// Ugly imperative way which contains duplicates
let mutable nIndex = 0
for n in items do
nIndex <- nIndex + 1
let mutable mIndex = nIndex
for m in items.[nIndex..] do
mIndex <- mIndex + 1
if n + m = C then do
printfn "Case #%A: %A %A" case nIndex mIndex
case <- case + 1
I would like to find out items which add up to C value but not in a usual imperative way - I want functional approach.
You don't specify how you would solve the problem, so it's hard to give advices.
Regarding reading inputs, you can express it as a series of transformation on Seq. High-order functions from Seq module are very handy:
let data =
"../../../../data/A-small-practice.in"
|> System.IO.File.ReadLines
|> Seq.skip 1
|> Seq.windowed 3
|> Seq.map (fun lines -> let C = int(lines.[0])
let L = int(lines.[1])
let items = lines.[2].Split([|' '|]) |> Array.map int
(C, L, items))
UPDATE:
For the rest of your example, you could use sequence expression. It is functional enough and easy to express nested computations:
let results =
seq {
for (C, _, items) in data do
for j in 1..items.Length-1 do
for i in 0..j-1 do
if items.[j] + items.[i] = C then yield (i, j)
}
Seq.iteri (fun case (i, j) -> printfn "Case #%A: %A %A" case i j) results
in the following code, does array of array A = B?
let A = Array.init 3 (fun _ -> Array.init 2 (fun _ -> 0))
let defaultCreate n defaultValue = Array.init n (fun _ -> defaultValue)
let B = defaultCreate 3 (defaultCreate 2 0)
if I assign values to A and B, they are different ,what happened? thanks.
for i = 0 to 2 do
for j = 0 to 1 do
A.[i].[j] <-i + j
B.[i].[j] <-i + j
printfn "%A vs %A" A B
A = [|[|0; 1|]; [|1; 2|]; [|2; 3|]|] and B = [|[|2; 3|]; [|2; 3|]; [|2; 3|]|]
let B = defaultCreate 3 (defaultCreate 2 0)
You create an array and then you use this array as values for each cell.
It's as if you did something like this:
let a = [|1; 2; 3; 4|]
let b = [|a; a; a; a|]
The same array a is used for every cell (think pointer to a is you're used to C). Thus, modifying b.[0].[1] will change every a.[1].
In my sample:
> b.[0].[1] <- 10;;
val it : unit = ()
> b;;
[|[|1; 10; 3; 4|]; [|1; 10; 3; 4|]; [|1; 10; 3; 4|]; [|1; 10; 3; 4|]|]
The same thing happens with your code.
They are not the same.
Arrays are reference types, and are stored on the heap. When you create an array with another array as the default value, you are storing references to the same array, over and over again.
Numbers are another thing. They are immutable, and are stored by value, on the stack. So you can't change the value of 1 to anything other than 1.
To create an "jagged" array, you need to call Array.init from inside the initializer to the first Array.init call, to create new arrays for each slot.
Also; You could use Array.create if you do want to have the same value in every slot. Be careful about reference types though.
let A = Array.init 3 (fun _ -> Array.create 2 0)