Reputation: 463
I wrote the following code to extract the values of the ID fields in a sequence of dictionaries and return these as a set - basically I'm looking for the PK values for rows in a db table that I've used to populate a dictionary (1 dict per table row). Below the code is some sample data that is loaded into the dictionary sequences.
While the code below works the style probably could be more functional - I had to resort to using a mutable list to build the result set. So it does not feel right to me.
Anyone care to offer an improved, more functional solution here.
// Extract the PK values from a dictionary and create a key set from these data values
// The expected result here is: set ["PK1"; "PK2"; "PK3"; "PK4"]
let get_keyset (tseq:seq<Dictionary<string,string>>) =
let mutable setres =[]
for x in tseq do
for KeyValue(k,v) in x do
// Extract ID values/keys from each dict
setres <- x.Item("ID")::setres
setres |> List.rev |> Set.ofList
// Sample Data
// First Tuple is PK/ID value
let tabledata = [
[("ID", "PK1"); ("a2","aa"); ("a3", "aaa"); ("a4", "aaaa") ]
[("ID", "PK2"); ("b2","bb"); ("b3", "bbb"); ("b4", "bbbb") ]
[("ID", "PK3"); ("c2","cc"); ("c3", "ccc"); ("c4", "cccc") ]
[("ID", "PK4"); ("d2","dd"); ("d3", "ddd"); ("d4", "dddd") ]
]
//generate dict sequence from datasets
let gendictseq tabledata =
seq {
for tl in tabledata do
let ddict = new Dictionary<string,string>()
for (k,v) in tl do
ddict.Add(k,v)
yield ddict
}
Upvotes: 1
Views: 318
Reputation: 62975
Your get_keyset
looks quite convoluted to me. This is considerably more succinct:
let get_keyset tseq =
tseq |> Seq.map (fun (x:Dictionary<_,_>) -> x.["ID"]) |> set
For gendictseq
, I would personally prefer higher-order functions over a sequence expression, but that is largely a matter of taste:
let gendictseq tabledata =
tabledata
|> Seq.map (fun table ->
(Dictionary<_,_>(), table)
||> List.fold (fun dict keyValue -> dict.Add keyValue; dict))
Upvotes: 3
Reputation: 33637
Functionally this operation is map as shown below:
let get_keyset_new (tseq:seq<Dictionary<string,string>>) =
let s = tseq |> Seq.map (fun i -> i |> Seq.map (fun e -> i.Item("ID") ) )
seq {
for i in s do
yield! i
} |> Set.ofSeq
Upvotes: 0
Reputation: 17119
Using a ResizeArray
(List<T>
in C#) is better than a mutable list variable:
let getKeyset (tseq:seq<Dictionary<string,string>>) =
let setres = new ResizeArray<string>()
for x in tseq do
for KeyValue(k,v) in x do
setres.Add(x.["ID"])
setres |> Set.ofSeq
or use the more functional sequence computation:
let getKeyset2 (tseq:seq<Dictionary<string,string>>) =
seq {
for x in tseq do
for KeyValue(k,v) in x do
yield x.["ID"]
}
|> Set.ofSeq
Upvotes: 1