When I try to evaluate the following code in F# interactive console I get three separated chart windows (one for chartA, one for chartB and one for combined chart). How to prevent of displaying chart every time it's created? I want to display only the combined chart in single chart window.
let chartA = setA |> Chart.Point |> Chart.WithSeries.Style(System.Drawing.Color.Orange)
let chartB = setB |> Chart.Point |> Chart.WithSeries.Style(System.Drawing.Color.Gold)
let chartC = Chart.Combine [|chartA; chartB|]
You can use scope
let chartC =
let chartA = setA |> Chart.Point |> Chart.WithSeries.Style(System.Drawing.Color.Orange)
let chartB = setB |> Chart.Point |> Chart.WithSeries.Style(System.Drawing.Color.Gold)
Chart.Combine [|chartA; chartB|]
Or without the locals
let chartC (setA:seq<float*float>) (setB:seq<float*float>) =
[| setA |> Chart.Point |> Chart.WithSeries.Style(System.Drawing.Color.Orange) ;
setB |> Chart.Point |> Chart.WithSeries.Style(System.Drawing.Color.Gold) |]
|> Chart.Combine
Related
I am trying to use FSharp.Data's HTML Parser to extract a string List of links from href attributes.
I can get the links printed out to console, however, i'm struggling to get them into a list.
Working snippet of a code which prints the wanted links:
let results = HtmlDocument.Load(myUrl)
let links =
results.Descendants("td")
|> Seq.filter (fun x -> x.HasClass("pagenav"))
|> Seq.map (fun x -> x.Elements("a"))
|> Seq.iter (fun x -> x |> Seq.iter (fun y -> y.AttributeValue("href") |> printf "%A"))
How do i store those strings into variable links instead of printing them out?
Cheers,
On the very last line, you end up with a sequence of sequences - for each td.pagenav you have a bunch of <a>, each of which has a href. That's why you have to have two nested Seq.iters - first you iterate over the outer sequence, and on each iteration you iterate over the inner sequence.
To flatten a sequence of sequences, use Seq.collect. Further, to convert a sequence to a list, use Seq.toList or List.ofSeq (they're equivalent):
let a = [ [1;2;3]; [4;5;6] ]
let b = a |> Seq.collect id |> Seq.toList
> val b : int list = [1; 2; 3; 4; 5; 6]
Applying this to your code:
let links =
results.Descendants("td")
|> Seq.filter (fun x -> x.HasClass("pagenav"))
|> Seq.map (fun x -> x.Elements("a"))
|> Seq.collect (fun x -> x |> Seq.map (fun y -> y.AttributeValue("href")))
|> Seq.toList
Or you could make it a bit cleaner by applying Seq.collect at the point where you first encounter a nested sequence:
let links =
results.Descendants("td")
|> Seq.filter (fun x -> x.HasClass("pagenav"))
|> Seq.collect (fun x -> x.Elements("a"))
|> Seq.map (fun y -> y.AttributeValue("href"))
|> Seq.toList
That said, I would rather rewrite this as a list comprehension. Looks even cleaner:
let links = [ for td in results.Descendants "td" do
if td.HasClass "pagenav" then
for a in td.Elements "a" ->
a.AttributeValue "href"
]
Let's say I have two lists:
let listOfValues = [100..105] //can be list of strings or whatever
let indexesToSortBy = [1;2;0;4;5;3]
Now I need listOfValues_sorted: 102;100;101;105;103;104
It can be done with zip and "conversion" to Tuple:
let listOfValues_sorted = listOfValues
|> Seq.zip indexesToSortBy
|> Seq.sortBy( fun x-> fst x)
|> Seq.iter(fun c -> printfn "%i" (snd c))
But I guess, there is better solution for that?
I think your solution is pretty close. I would do this
let listOfValues_sorted =
listOfValues
|> Seq.zip indexesToSortBy
|> Seq.sortBy fst
|> Seq.toList
|> List.unzip
|> List.head
you can collapse fun x -> fst x into simply fst. And then unzip and get what ever list you want
If indexesToSortBy is a complete set of indexes you could simply use:
indexesToSortBy |> List.map (fun x -> listOfValues |> List.item x )
Your example sounds precisely what the List.permute function is for:
let listOfValues = [100..105]
let indexesToSortBy = [|1;2;0;4;5;3|] // Note 0-based indexes
listOfValues |> List.permute (fun i -> indexesToSortBy.[i])
// Result: [102; 100; 101; 105; 103; 104]
Two things: First, I made indexesToSortBy an array since I'll be looking up a value inside it N times, and doing that in a list would lead to O(N^2) run time. Second, List.permute expects to be handed a 0-based index into the original list, so I subtracted 1 from all the indexes in your original indexToSortBy list. With these two changes, this produces exactly the same ordering as the let listOfValues_sorted = ... example in your question.
How do I split up a collection by number of elements?
For example, if I have the following:
0,1,2,3,4,5,6,7,8
How could I partition the collection into 3 sets:
0,1,2
3,4,5
6,7,8
NOTE:
F# is extremely foreign to me. So forgive my ignorance.
Here's a TicTacToe exercise that I am trying to learn F# with.
In the code, I am using Seq.take and Seq.skip.
How could I write this differently?
module TicTacToe
open FsUnit
open NUnit.Framework
[<Test>]
let ``player has connected row`` () =
let grid = Map.empty
.Add(0, true).Add(1, true).Add(2, true)
.Add(3, true).Add(4, false).Add(5, true)
.Add(6, true).Add(7, true).Add(8, true)
let firstRowIsStreak = grid
|> Seq.take 3
|> Seq.forall (fun x -> x.Value = true)
let secondRowIsStreak = grid
|> Seq.skip 3
|> Seq.take 3
|> Seq.forall (fun x -> x.Value = true)
let thirdRowIsStreak = grid
|> Seq.skip 6
|> Seq.take 3
|> Seq.forall (fun x -> x.Value = true)
firstRowIsStreak |> should equal true
secondRowIsStreak |> should equal false
thirdRowIsStreak |> should equal true
If you have F# 4.0 you can use Seq.chunkBySize
Seq.chunkBySize 3 (seq [0;1;2;3;4;5;6;7;8])
val it : seq<int []> = seq [[|0; 1; 2|]; [|3; 4; 5|]; [|6; 7; 8|]]
I have the following problem and I hope somebody can help me.
Short description of the problem: i need to store a (string A, float B, float C) triad into a suitable container. The triad originates fomr a double "for" loop.
But the essential point is that I will need to slice this container when the loops are over to perform other operations.
An example that can be executed from the .fsx shell (using Deedle frames) follows. The triad is what is beeing printed on the screen.
open Deedle
let categorical_variable = [| "A"; "B"; "C"; "A"; "B"; "C"; |]
let vec_1 = [| 15.5; 14.3; 15.5; 14.3; 15.5; 14.3; |]
let vec_2 = [| 114.3; 17.5; 9.3; 88.7; 115.5; 12.3; |]
let dframe = frame ["cat" =?> Series.ofValues categorical_variable
"v1" =?> Series.ofValues vec_1
"v2" =?> Series.ofValues vec_2 ]
let distinct_categorical_variables = categorical_variable |> Array.toSeq |> Seq.distinct |> Seq.toArray
let mutable frame_slice : Frame<int, string> = Frame.ofRows []
let mutable frame_slice_vec_1 : float[] = Array.empty
let mutable frame_slice_vec_1_distinct : float[] = Array.empty
for cat_var in distinct_categorical_variables do
frame_slice <- (dframe |> Frame.filterRowValues (fun row -> row.GetAs "cat" = cat_var))
frame_slice_vec_1 <- (frame_slice?v1).Values |> Seq.toArray
frame_slice_vec_1_distinct <- (frame_slice_vec_1 |> Array.toSeq |> Seq.distinct |> Seq.toArray)
for vec_1_iter in frame_slice_vec_1_distinct do
printfn "%s, %f, %f \n" cat_var vec_1_iter (Array.average ((frame_slice?v2).Values |> Seq.toArray) ) |> ignore
So, is there any suitable object where to store this triad? I saw Array3d objects, but I don't think they are the right solution cause A, B and C of my triad have different types.
Many thanks in advance.
you probably want a sequence expression with tuples:
let mySequence =
seq { for cat_var in distinct_categorical_variables do
...
for vec_1_iter in ... do
yield cat_var, vec_1_iter, Array.average ... }
// then use it like
for cat_var, vec_1_iter, result in mySequence do
...
In order to get comfortable with Deedle I made up a CSV file that represents a log of video rentals.
RentedOn,Shop,Title
12/dec/2013 00:00:00,East,Rambo
12/dec/2013 00:00:00,West,Rocky
12/dec/2013 00:00:00,West,Rambo
12/dec/2013 00:00:00,East,Rambo
13/dec/2013 00:00:00,East,Rocky
13/dec/2013 00:00:00,East,Rocky
13/dec/2013 00:00:00,East,Rocky
14/dec/2013 00:00:00,West,Rocky 2
I have the following function, that groups the rentals by Shop (East or West):
let overview =
__SOURCE_DIRECTORY__ + "/rentallog.csv"
|> Frame.ReadCsv
|> Frame.groupRowsByString "Shop"
|> Frame.nest
|> Series.map (fun dtc df ->
df.GetSeries<string>("Title") |> Series.groupBy (fun k v -> v)
|> Frame.ofColumns |> Frame.countValues )
|> Frame.ofRows
I'd like to be able to filter the rows by the date in the RentedOn col, however, I'm not sure how to do this. I know its probably using the Frame.filterRowValues function but I'm unsure the best way to use this. Any guidance on how to filter would be appreciated.
Update based on #jeremyh advice
let overview rentedOnDate =
let addRentedDate (f:Frame<_,_>) =
f.AddSeries ("RentedOnDate", f.GetSeries<DateTime>("RentedOn"))
f
__SOURCE_DIRECTORY__ + "/rentallog.csv"
|> Frame.ReadCsv
|> addRentedDate
|> Frame.filterRowValues (fun row -> row.GetAs<DateTime>("RentedOnDate") = rentedOnDate)
|> Frame.groupRowsByString "Shop"
|> Frame.nest
|> Series.map (fun dtc df ->
df.GetSeries<string>("Title") |> Series.groupBy (fun k v -> v)
|> Frame.ofColumns |> Frame.countValues )
|> Frame.ofRows
Thanks,
Rob
Hey I think that you might get a faster answer if you add an f# tag to your question too.
I used the following link to answer your question which has some helpful examples.
This is the solution I came up with. Please note that I added a new column RentedOnDate that actually has a DateTime type that I do the filtering on.
let overview rentedOnDate =
let rentalLog =
__SOURCE_DIRECTORY__ + "/rentallog.csv"
|> Frame.ReadCsv
rentalLog
|> Frame.addSeries "RentedOnDate" (rentalLog.GetSeries<DateTime>("RentedOn"))
|> Frame.filterRowValues (fun row -> row.GetAs<DateTime>("RentedOnDate") = rentedOnDate)
|> Frame.groupRowsByString "Shop"
|> Frame.nest
|> Series.map (fun dtc df ->
df.GetSeries<string>("Title") |> Series.groupBy (fun k v -> v)
|> Frame.ofColumns |> Frame.countValues )
|> Frame.ofRows
// Testing
overview (DateTime.Parse "12/dec/2013 00:00:00")