I am trying to write a list comprehension in F# and can't get it to compile:
[for x in xs do
let y = f(x)
when g(y) -> y]
Is there any way to save an intermediate computation in the middle of a list comprehension? How can I rework this list comprehension so that it compiles?
I would just skip the list comprehension.
let ys = xs |> List.map f |> List.filter g
However it is simple enough to get your code working.
let ys = [ for x in xs do
let y = f(x)
if g(y) then yield y ]
To expand on #ChaosPandion's solution, you could also write this using List.choose -- think of it as a combination of List.map and List.filter which avoids creating an extra list (i.e., instead of creating a list with List.map just to pass it to List.filter).
let ys =
xs
|> List.choose (fun x ->
let y = f x
if g y then Some y else None)
Related
I'm making a function that takes a Map and generates all the possible swaps of values.
let mutations setup =
let setupList = setup |> Map.toList
[for x in 0..(setupList.Length-1) do
for y in x..(setupList.Length-1) do
yield (x, y)]
|> Seq.map (fun (x,y) ->
setupList
|> swapSndAt x y
|> Map.ofList)
|> Seq.distinct
Here is the code for swapSndAt:
let swapSndAt i1 i2 xs =
let f1,s1 = xs |> List.item i1
let f2,s2 = xs |> List.item i2
xs |> List.mapi (fun i x ->
if i = i1 then f1,s2
else if i = i2 then f2,s1
else x)
When I run this, I get an System.ArgumentException: The index was outside the range of elements in the list. at the point where I am calling List.item in swapSndAt.
How can that be, since the List comprehension makes sure to watch the bounds?
let allEmpty xs =
xs |> List.maxBy (fun x -> x |> List.length) = 0
that doesn't type check.
this does:
let allEmpty xs =
xs |> List.maxBy (fun x -> x |> List.length) = []
Doesn't maxBy return an int?
List.maxBy returns the larges element based on the function you give it.
In you case xs is a 'a list list - a list of lists. So you are looking for the longest list in the list of lists.
If you wanted the length of the largest list you would map the length first and then use max.
let allEmpty xs =
xs
|> List.map (fun x -> x |> List.length) //Get the length of each list in the list
|> List.max = 0 //See if the largest is empty, if so all are empty.
Although this feels a much more natural way to express the intent of the function:
let allEmpty xs =
xs |> List.forall ((=) [])
Or more verbose:
let allEmpty xs =
xs |> List.forall (fun l -> l |> List.length = 0)
x in this case is a list and it is returning a list with the largest length. (xs is a list of lists.)
If you want to test list length you need something like this
let allEmpty xs =
xs
|> List.map (fun x -> x |> List.length)
|> List.maxBy id = 0
I want to flatten a Vector3 list to float32 list.
[Vector(1.,2.,3.);Vector(1.,2.,3.)] to [1.;2.;3.;1.;2.;3.]
I have done it successfully with the following function
let rec convert_vec3 (v: Vector3 list) acc =
match v with
| [] -> acc
| x :: xs-> convert_vec3 xs [x.X; x.Y;x.Z] # acc
How would this look with List.fold?
The equivalent of your convert_vec3 function would be
List.fold (fun acc (v:Vector) -> [v.X; v.Y; v.Z] # acc) [] input
But, as mydogisbox mentions, List.collect might be better as that will give you the list in the right order, which your convert_vec3 function and List.fold equivalent will not do.
List.collect (fun (v:Vector) -> [v.X;v.Y;v.Z]) input
The answer of #mydogisbox is good and valid, but you can use List.fold as well. Please note that your recursive function gathers the values in reverse order. To avoid that, I would actually recommend List.foldBack:
([Vector(1.,2.,3.);Vector(1.,2.,3.)], [])
||> List.foldBack (fun v acc -> v.X :: v.Y :: v.Z :: acc)
// val it : float list = [1.0; 2.0; 3.0; 1.0; 2.0; 3.0]
I think what you want is List.collect not List.fold:
> List.collect (fun x->x |> List.map (float32)) [[1.0];[2.0];[3.0]];;
val it : float32 list = [1.0f; 2.0f; 3.0f]]
Replace the (fun x->x |> List.map (float32)) with a mapping between your vectors and a list of the resulting values for that vector
Hullo all.
I am a C# programmer, exploring F# in my free time. I have written the following little program for image convolution in 2D.
open System
let convolve y x =
y |> List.map (fun ye -> x |> List.map ((*) ye))
|> List.mapi (fun i l -> [for q in 1..i -> 0] # l # [for q in 1..(l.Length - i - 1) -> 0])
|> List.reduce (fun r c -> List.zip r c |> List.map (fun (a, b) -> a + b))
let y = [2; 3; 1; 4]
let x = [4; 1; 2; 3]
printfn "%A" (convolve y x)
My question is: Is the above code an idiomatic F#? Can it be made more concise? (e.g. Is there some shorter way to generate a filled list of 0's (I have used list comprehension in my code for this purpose)). Any changes that can improve its performance?
Any help would be greatly appreciated. Thanks.
EDIT:
Thanks Brian. I didn't get your first suggestion. Here's how my code looks after applying your second suggestion. (I also abstracted out the list-fill operation.)
open System
let listFill howMany withWhat = [for i in 1..howMany -> withWhat]
let convolve y x =
y |> List.map (fun ye -> x |> List.map ((*) ye))
|> List.mapi (fun i l -> (listFill i 0) # l # (listFill (l.Length - i - 1) 0))
|> List.reduce (List.map2 (+))
let y = [2; 3; 1; 4]
let x = [4; 1; 2; 3]
printfn "%A" (convolve y x)
Anything else can be improved? Awaiting more suggestions...
As Brian mentioned, the use of # is generally problematic, because the operator cannot be efficiently implemented for (simple) functional lists - it needs to copy the entire first list.
I think Brians suggestion was to write a sequence generator that would generate the list at once, but that's a bit more complicated. You'd have to convert the list to array and then write something like:
let convolve y x =
y |> List.map (fun ye -> x |> List.map ((*) ye) |> Array.ofList)
|> List.mapi (fun i l -> Array.init (2 * l.Length - 1) (fun n ->
if n < i || n - i >= l.Length then 0 else l.[n - i]))
|> List.reduce (Array.map2 (+))
In general, if performance is an important concern, then you'll probably need to use arrays anyway (because this kind of problem can be best solved by accessing elements by index). Using arrays is a bit more difficult (you need to get the indexing right), but perfectly fine approach in F#.
Anyway, if you want to write this using lists, then here ara some options. You could use sequence expressions everywhere, which would look like this:
let convolve y (x:_ list) =
[ for i, v1 in x |> List.zip [ 0 .. x.Length - 1] ->
[ yield! listFill i 0
for v2 in y do yield v1 * v2
yield! listFill (x.Length - i - 1) 0 ] ]
|> List.reduce (List.map2 (+))
... or you can also combine the two options and use a nested sequence expression (with yield! to generate zeros and lists) in the lambda function that you're passing to List.mapi:
let convolve y x =
y |> List.map (fun ye -> x |> List.map ((*) ye))
|> List.mapi (fun i l ->
[ for _ in 1 .. i do yield 0
yield! l
for _ in 1 .. (l.Length - i - 1) do yield 0 ])
|> List.reduce (List.map2 (+))
The idiomatic solution would be to use arrays and loops just as you would in C. However, you may be interested in the following alternative solution that uses pattern matching instead:
let dot xs ys =
Seq.map2 (*) xs ys
|> Seq.sum
let convolve xs ys =
let rec loop vs xs ys zs =
match xs, ys with
| x::xs, ys -> loop (dot ys (x::zs) :: vs) xs ys (x::zs)
| [], _::(_::_ as ys) -> loop (dot ys zs :: vs) [] ys zs
| _ -> List.rev vs
loop [] xs ys []
convolve [2; 3; 1; 4] [4; 1; 2; 3]
Regarding the zeroes, how about e.g.
[for q in 0..l.Length-1 -> if q=i then l else 0]
(I haven't tested to verify that is exactly right, but hopefully the idea is clear.) In general, any use of # is a code smell.
Regarding overall performance, for small lists this is probably fine; for larger ones, you might consider using Seq rather than List for some of the intermediate computations, to avoid allocating as many temporary lists along the way.
It looks like maybe the final zip-then-map could be replaced by just a call to map2, something like
... fun r c -> (r,c) ||> List.map2 (+)
or possibly even just
... List.map2 (+)
but I'm away from a compiler so haven't double-checked it.
(fun ye -> x |> List.map ((*) ye))
Really ?
I'll admit |> is pretty, but you could just wrote :
(fun ye -> List.map ((*) ye) x)
Another thing that you could do is fuse the first two maps. l |> List.map f |> List.mapi g = l |> List.mapi (fun i x -> g i (f x)), so incorporating Tomas and Brian's suggestions, you can get something like:
let convolve y x =
let N = List.length x
y
|> List.mapi (fun i ye ->
[for _ in 1..i -> 0
yield! List.map ((*) ye) x
for _ in 1..(N-i-1) -> 0])
|> List.reduce (List.map2 (+))
I am trying to think of an elegant way of getting a random subset from a set in F#
Any thoughts on this?
Perhaps this would work: say we have a set of 2x elements and we need to pick a subset of y elements. Then if we could generate an x sized bit random number that contains exactly y 2n powers we effectively have a random mask with y holes in it. We could keep generating new random numbers until we get the first one satisfying this constraint but is there a better way?
If you don't want to convert to an array you could do something like this. This is O(n*m) where m is the size of the set.
open System
let rnd = Random(0);
let set = Array.init 10 (fun i -> i) |> Set.of_array
let randomSubSet n set =
seq {
let i = set |> Set.to_seq |> Seq.nth (rnd.Next(set.Count))
yield i
yield! set |> Set.remove i
}
|> Seq.take n
|> Set.of_seq
let result = set |> randomSubSet 3
for x in result do
printfn "%A" x
Agree with #JohannesRossel. There's an F# shuffle-an-array algorithm here you can modify suitably. Convert the Set into an array, and then loop until you've selected enough random elements for the new subset.
Not having a really good grasp of F# and what might be considered elegant there, you could just do a shuffle on the list of elements and select the first y. A Fisher-Yates shuffle even helps you in this respect as you also only need to shuffle y elements.
rnd must be out of subset function.
let rnd = new Random()
let rec subset xs =
let removeAt n xs = ( Seq.nth (n-1) xs, Seq.append (Seq.take (n-1) xs) (Seq.skip n xs) )
match xs with
| [] -> []
| _ -> let (rem, left) = removeAt (rnd.Next( List.length xs ) + 1) xs
let next = subset (List.of_seq left)
if rnd.Next(2) = 0 then rem :: next else next
Do you mean a random subset of any size?
For the case of a random subset of a specific size, there's a very elegant answer here:
Select N random elements from a List<T> in C#
Here it is in pseudocode:
RandomKSubset(list, k):
n = len(list)
needed = k
result = {}
for i = 0 to n:
if rand() < needed / (n-i)
push(list[i], result)
needed--
return result
Using Seq.fold to construct using lazy evaluation random sub-set:
let rnd = new Random()
let subset2 xs = let insertAt n xs x = Seq.concat [Seq.take n xs; seq [x]; Seq.skip n xs]
let randomInsert xs = insertAt (rnd.Next( (Seq.length xs) + 1 )) xs
xs |> Seq.fold randomInsert Seq.empty |> Seq.take (rnd.Next( Seq.length xs ) + 1)