<#[for i in linq.TrueIncidents -> i.RecTime, i.Name ] #> |> query |> Array.ofSeq
How can I get counts of different names ?
just count(Name) where Name = somename...
I think first I must select form here all Names with |> Seq.distinctBy(fun x -> x.Name)
and then make Seq.Count() different selects where Name will be one of names and then union all the selects ... really wierd way.
Or I can use it as object later with closure with int ref counters for each distincted Name...
I understand that my explanation could be some messy , so ask if you can't get it. I want to know is there any way to use Count(Name) where Name = OneOfNames inside closure or linq2sql ?
I can't compile to verify that this works at the moment, but try the following:
<# linq.TrueIncidents
|> Seq.groupBy (fun i -> i.Name)
|> Seq.map (fun (name, is') -> name, Seq.length is') #>
|> query
|> Map.ofSeq
This should give you a Map<string, int> of each name and its respective number of occurrences.
Related
Lets say you had a requirement to group a sequence into a sequence of tuples. Each tuple is a key*seq. So in a sense, the result is a sequence of sequences.
All pretty standard so far.
What if you wanted to further group each sub sequence by some other key? It would be easy enough to map another groupby function onto each element of your sequence of sequences. You would then have a sequence of sequences of sequences.
Starting to get slightly hairy.
What if you wanted to group it even further?
Would it be possible to write a function that can take in a key generating function and an arbitrary sequence, and recursively unwraps the layers and then adds another layer of grouping using the keyFunction?
I suspect the answer is no, because the recursive function would not have a well defined type.
My attempt at this, to further illustrate the idea:
let rec recursiveGrouper keyFunction aSeq =
let first = Seq.head aSeq
match first with
| ((a:'a), _) -> Seq.map (fun (b,(c:seq<'c>)) -> (b, recursiveGrouper keyFunction c)) aSeq
| _ -> Seq.groupBy keyFunction aSeq
EDIT:
Lets add an example of how this might work, it it were possible
type FruitRecord = {Fruit:string; Number:int; SourceFarm:string; Grade:float}
let key1 fr =
fr.Fruit
let key2 fr =
fr.SourceFarm
let key3 fr =
match fr.Grade with
|f when f > 5.0 -> "Very Good"
|f when f > 2.5 -> "Not bad"
|_ -> "Garbage"
Lets say we have a whole bunch of fruit records in a sequence. We want to group them by type of fruit.
One way would be to say
let group1 = fruitRecs |> Seq.groupBy key1
Using our recursive function, this would be
let group1 = recursiveGrouper key1 fruitRecs
Next, lets say we want to group each of the items in the groups of group1 by source farm.
We could say
let group2 =
group1
|> Seq.map (fun (f, s) -> (f, Seq.groupBy key2 s))
Using our recursive function it would be
let group2 = recursiveGrouper key2 group1
And we could go further and group by Grade by saying
let group3 = recursiveGrouper key3 group2
Actually there are some ways to make that recursive function work, using static constraints. Here's a small example:
// If using F# lower than 4.0, use this definition of groupBy
module List =
let groupBy a b = Seq.groupBy a (List.toSeq b) |> Seq.map (fun (a, b) -> a, Seq.toList b) |> Seq.toList
type A = class end // Dummy type
type B = class end // Dummy type
type C =
inherit B
static member ($) (_:C, _:A ) = fun keyFunction -> () // Dummy overload
static member ($) (_:C, _:B ) = fun keyFunction -> () // Dummy overload
static member ($) (_:B, aSeq) = fun keyFunction -> List.groupBy keyFunction aSeq // Ground case overload
static member inline ($) (_:C, aSeq) = fun keyFunction -> List.map (fun (b, c) -> b, (Unchecked.defaultof<C> $ c) keyFunction) aSeq
let inline recursiveGrouper keyFunction aSeq = (Unchecked.defaultof<C> $ aSeq) keyFunction
// Test code
type FruitRecord = {Fruit:string; Number:int; SourceFarm:string; Grade:float}
let key1 fr = fr.Fruit
let key2 fr = fr.SourceFarm
let key3 fr =
match fr.Grade with
|f when f > 5.0 -> "Very Good"
|f when f > 2.5 -> "Not bad"
|_ -> "Garbage"
let fruitRecs = [
{Fruit = "apple" ; Number = 8; SourceFarm = "F"; Grade = 5.5}
{Fruit = "apple" ; Number = 5; SourceFarm = "F"; Grade = 4.5}
{Fruit = "orange"; Number = 8; SourceFarm = "F"; Grade = 5.5}
]
let group1 = recursiveGrouper key1 fruitRecs
let group2 = recursiveGrouper key2 group1
let group3 = recursiveGrouper key3 group2
I don't think you could write it as a recursive function with the sort of constraints you put on yourself - that is:
A tuple 'key * seq<'value> representing the grouping,
A heterogeneous key function (or a collection thereof) - this is what I understand by "group each sub sequence by some other key".
You could make some leeway if you would represent the grouping as an actual tree type (rather than an ad-hoc tree built from tuples) - that way you'd have a well-defined recursive result type to go with your recursive function.
If at that point you would be able to also compromise on the key function to make it homogeneous (worst case - producing a hashcode), you should be able to express what you want within the type system.
You certainly could have a non-recursive grouping function that takes a grouped sequence and puts another level of grouping on top of it - like the one below:
module Seq =
let andGroupBy (projection: 't -> 'newKey) (source: seq<'oldKey * seq<'t>>) =
seq {
for key, sub in source do
let grouped = Seq.groupBy projection sub
for nkey, sub in grouped do
yield (key, nkey), sub
}
Using your FruitRecord example:
values
|> Seq.groupBy key1
|> Seq.andGroupBy key2
|> Seq.andGroupBy key3
First off, I would like to make you all aware that I'm very new to Haskell, so to increase knowledge etc, I've been trying out questions and I'm pretty stuck on one. I think I'm nearly there but some more experienced advice would be appreciated. Here's the question:
A sporting team is represented by it's name and the amount of points they scored in their last games like so ("Newcastle",[3,3,3,0]). This data is modelled by the type definitions:
type TName = String
type Points = [Int]
type Team = (TName,Points)
From this I have to define the following function that orders one team higher than another if their points sum is greater:
sortPoints :: [Team] -> [Team]
This is what I've tried:
sortPoints :: [Team] -> [Team]
sortPoints [_,()] -> []
sortPoints [_,(x:xs)] = sum[x|x<-xs]
Once I get to here, I'm not too sure how to go about adding the conditions to check the points sum, any pointers would be greatly appreciated as I'm still coming to terms with a lot of Haskell features.
Note: This post is written in literate Haskell. You can save it as Team.lhs and try it. That being said, it's basically a longer version of Carsten's comment. If you still try to figure things out, use hoogle and look for the functions, although it's fine if you manage things with sortBy solely first.
First of all, we're going to work on lists, so you want to import Data.List.
> module Team where
> import Data.List
It contains a function called sortBy:
sortBy :: (a -> a -> Ordering) -> [a] -> [a]
The first argument of sortBy should be a function that compares two elements of your list and returns
LT if the first is less than the second,
EQ if the both are equal,
GT if the first is greater than the second.
So we need something that that takes two teams and returns their ordering:
> -- Repeating your types for completeness
> type TName = String
> type Points = [Int]
> type Team = (TName, Points)
>
> compareTeams :: Team -> Team -> Ordering
Now, you want to compare teams based on their sum of their points. You don't need their name, so you can capture just the second part of the pair:
> compareTeams (_, s1) (_, s2) =
We need the sum of the points, so we define sum1 and sum2 to be the respective sums of the teams:
> let sum1 = sum s1
> sum2 = sum s2
Now we can compare those sums:
in if sum1 < sum2
then LT
else if sum1 == sum2
then EQ
else GT
However, that's rather verbose, and there's already a function that has type Ord a => a -> a -> Ordering. It's called compare and part of the Prelude:
> in sum1 `compare` sum2
That's a lot more concise. Now we can define sortTeams easily:
> sortTeams :: [Team] -> [Team]
> sortTeams = sortBy compareTeams
And that's it, we're done!
Fine, I lied, we're not 100% done. The module Data.Ord contains a function called comparing that's rather handy:
comparing :: Ord b => (a -> b) -> a -> a -> Ordering
comparing f x y = f x `compare` f y -- or similar
Together with snd and sum you can define sortTeams in a single line:
sortTeams = sortBy (comparing $ sum . snd)
The alternative on mentioned by Carsten is on from Data.Function:
sortTeams = sortBy (compare `on` sum . snd)
In OCaml, I have a list of strings that contains names of towns (Something like "1-New York; 2-London; 3-Paris"). I need to ask the user to type a number (if they want London they have to type 2).
I want to raise an exception message saying that the town is not valid, if the person types for example "4", in the example.
I tried this, but it doesn't work :
let chosenTown = match int_of_string (input_line stdin) with
| x > (length listOfTowns) -> raise (Err "Not a valid town")
What's the good way to code "if the chosen number is bigger than the length of the list then raise the error" ??
Pattern can't contain arbitrary expressions. It can be a constant, a constructor name, record field inside curly braces, list, array, etc.
But patterns can be guarded, e.g.
match int_of_string (input_line stding) with
| x when x >= length listOfTowns ->
invalid_arg "the number is too large"
| x -> List.nth listOfTowns x
To complete the answer, patter matching relies on unification and does not expect assertion (it is not the equivalent of a switch in C or so).
The idea is that you provide different "shapes" (patterns) that your term (the thing you match on) could have.
For a list for instance:
match l with
| e :: e' :: r -> (*...*)
| e :: r -> (*...*)
| [] -> (*...*)
It also had a binding effect, if you pass on, say, [1] (a very small list indeed), it won't match e :: e' :: r, but will match e :: r and then e = 1 and r = [].
As ivg said, you can add conditions, as booleans this time, thanks to the keyword when.
However, when manipulating lists like this, I would go for a recursive function:
let rec find_town n l =
match l with
| t :: _ when n = 1 -> t
| _ :: r -> find_town (n-1) r
| [] -> raise (Err "Not a valid town")
This is basically writing again List.nth but changing the exception that it raises.
I already sent the bug to fsbugs#microsoft.com but I also added this link to letter for additional description, code highlighting, discussions and maybe someone find some way to avoid it, because I really like it and want to use.
Code :
<# seq {for a in db.ArchiveAnalogs do
for d in db.Deltas do
if a.ID = d.ID then
if a.Value > d.DeltaLimit then
yield a.Date, d.AboveMessage
else if a.Value < d.DeltaLimit then
yield a.Date, d.BelowMessage}
#> |> query |> Array.ofSeq
Same error messages with update :
<# seq {for a in db.ArchiveAnalogs do
for d in db.Deltas do
if a.ID = d.ID && a.Value > d.DeltaLimit then
yield a.Date, d.AboveMessage
elif a.ID = d.ID && a.Value < d.DeltaLimit then
yield a.Date, d.BelowMessage}
#> |> query |> Array.ofSeq
Error message :
The following construct was used in query but is not recognised by the
F#-to-LINQ query translator: Call
(None,
System.Collections.Generic.IEnumerable1[System.Tuple2[System.DateTime,System.String]]
Singleton[Tuple2](System.Tuple2[System.DateTime,System.String]),
[NewTuple (PropertyGet (Some (a), System.DateTime Date, []),
PropertyGet (Some (d), System.String AboveMessage,
[]))]) This is not a valid query
expression. Check the specification of
permitted queries and consider moving
some of the query out of the quotation
Fixed
Code :
let px =
query <|
<# seq { for cl in db.Dictionaries -> cl }
|> Seq.filter(fun x -> x.ID_Line = l1 || x.ID_Line = l2) #>
|> fun pquery ->
query <|
<# seq { for cd in db.DeltaCompares do
for cl1 in pquery do
if cd.IID1 = cl1.IID then
for cl2 in pquery do
if cd.IID2 = cl2.IID then
yield cl1
yield cl2 } #>
|> List.ofSeq
Same error with update :
let p =
[for cl in db.Dictionaries -> cl]
|> Seq.filter(fun x -> x.ID_Line = l1 || x.ID_Line = l2)
|> fun pquery ->
<# seq { for cd in db.DeltaCompares do
for cl1 in pquery do
for cl2 in pquery do
if cd.IID1 = cl1.IID && cd.IID2 = cl2.IID then
yield cl1, cl2 } #>
|> query |> Seq.collect(fun a -> [fst a; snd a])
Error message :
The following construct was used in query but is not
recognised by the F#-to-LINQ query
translator: Call (None,
System.Collections.Generic.IEnumerable`1[LinqBase.Dictionary]
SingletonDictionary,
[cl1]) This is not a valid query expression. Check the specification of
permitted queries and consider moving
some of the query out of the quotation
fixed
I'm not sure if I do it correct so I also ask you to confirm if this is a bug or not a bug
In the first case, I think the F#-to-LINQ translator may be failing on nested if. Have you tried: (...)
EDIT [Second attempt]: It could also fail because we're using if without else clause. What if you always return something using option type and then filter out None values (there may be a way to make it nicer, but let's start with this):
<# seq {for a in db.ArchiveAnalogs do
for d in db.Deltas do
yield
if a.ID = d.ID && a.Value > d.DeltaLimit then
Some(a.Date, d.AboveMessage)
elif a.ID = d.ID a.Value < d.DeltaLimit then
Some(a.Date, d.BelowMessage)
else None }
#> |> query |> Seq.choose id |> Array.ofSeq
In the second case, it may be failing because of the for nested in if. I'd try this (...)
EDIT: This is actually incorrect use of LINQ (and it wouldn't work in C# too). The problem is that you're collecting some data in memory (pquery) and then passing this as an input to the LINQ (so that it would have to send the data back to the SQL server.
You can try writing it like this (BTW: I think using |> fun x -> is a weird construct when you can write the same thing simply just using let):
let pquery = <# db.Dictionaries
|> Seq.filter(fun x -> x.ID_Line = l1 || x.ID_Line = l2) #>
let px =
<# seq { for cd in db.DeltaCompares do
for p in %pquery do ... } |> query
This is using quotation splicing. For more information about this feature, see my article (search for splicing).
Teach me how can I improve my F# linq2sql seqences
here I'm using linq2sql but I think that I got problems with it.
and main problem is access by ID here in example I'm making 2 embedded for but I got very scary linq2 sql queries because I don't know is there some additional methods or ways to make it ...
member X.deltaArchive() = // Reacting on delta limits
seq { for a in db.ArchiveAnalogs do
for d in db.Deltas do
if a.ID = d.ID then
if a.Value > d.DeltaLimit then
yield d.AboveMessage
else if a.Value < d.DeltaLimit then
yield d.BelowMessage
} |> Array.ofSeq
So the complete question is : is there any way to make the same without using embedded cycles to find id conformity ?
Thank you.
Added :
using :
<# seq {for a in db.ArchiveAnalogs do
for d in db.Deltas do
if a.ID = d.ID then
if a.Value > d.DeltaLimit then
yield a.Date, d.AboveMessage
else if a.Value < d.DeltaLimit then
yield a.Date, d.BelowMessage}
#> |> query |> Array.ofSeq
got error :
The following construct was used in query but is not recognised by the F#-to-LINQ query translator:
Call (None,
System.Collections.Generic.IEnumerable`1[System.Tuple`2[System.DateTime,System.String]] Singleton[Tuple`2](System.Tuple`2[System.DateTime,System.String]),
[NewTuple (PropertyGet (Some (a), System.DateTime Date, []),
PropertyGet (Some (d), System.String AboveMessage, []))])
This is not a valid query expression. Check the specification of permitted queries and consider moving some of the query out of the quotation
offtopic : I must find solution because this is first google link about "F# linq2sql"
First of all, the snippet you wrote isn't really using LINQ to SQL. You're running the whole processing in memory, because F# doesn't select query operators based on type (as C# does). You need to mark the query explicitly to run it on SQL:
#r "FSharp.PowerPack.Linq.dll"
open Microsoft.FSharp.Linq
<# seq { for a in db.ArchiveAnalogs do ... } #> |> query
An alternative way to write what you want is to use Query.join function (from PowerPack). I believe the following should do the trick:
<# join db.ArchiveAnalogs db.Deltas (fun a -> a.ID) (fun d -> d.ID) (fun a d ->
if a.Value > d.DeltaLimit then
yield d.AboveMessage
else if a.Value < d.DeltaLimit then
yield d.BelowMessage ) #> |> query
(Although, I think that there is really no difference between using join and nested for - If you run this on SQL than it will likely optimize it to join anyway).