0
votes

In the following snippet I'm trying to extract the recid contained in a nested tuple which forms a dict key. The nested tuple format is (Int32, (boolean, boolean)) -

I'm looking for the value of the Int32 item (which is actually the Row ID for a db record).

In the match code below I'm trying to add the recid to a list, but first I am casting to the object to an integer.
However this produces the following error - not sure why?

Error: This runtime coercion or type test from type 'a to int32
involves an indeterminate type based on information prior to this program point. Runtime type tests are not allowed on some types. Further type annotations are needed. The dictionary being referenced here is defined as:

// Create Dict  
let rdict =  new Dictionary<_,_>()
// Add elements
rdict.Add( (x.["PatientID"],(true,true) ),ldiff) 

// Extract Dict items 
let reclist = new ResizeArray<int32>()
for KeyValue(k,v) in rdict do
match k with
    | ((recid,(true,true)) ->
     printfn "Found a matching Record: %A " recid;   // <- prints correct result
     let n = (recid:?> int32)                            // <- coercion error
         reclist.Add(n)
2
The line rdict.Add( (x.["PatientID"],(true,true) ) has a mismatched number of opening and closing parenthesis. What are the Dictionary's key and value types? Is int*(bool*bool) intended to be the key type only, or is int the key type and bool*bool the value type? Also, what is the actual type of x.["PatientID"]? Does that return an int or a boxed int (i.e., obj which can be cast to int)? - ildjarn
Oops - I goofed when posting the rdict.add line - now corrected. (I'm actually/building a list of row/col pairs as the dict value. The dict key is actually a composite (rid,(boolean,boolean)) value. (the booleans define whether the rec exists in a pair of tables). x.["PatientID"] is an (unboxed) int value retrieved from a db table. - BrendanC
Actually, one more question -- is it your intention to only copy the ids from rdict into reclist if their accompanying bool pair is true, true and not any other combination? - ildjarn
@ildjarn: I'm comparing 2 db tables here so for a reporting summary I want the option to build separate reclists for several different match conditions (e.g. Intersect Count; a not in b count; b not in a count). BTW I think boxing and unboxing the value may work (not sure why this should be required when the printfn handles the cvn correctly) - I need to test it further. - BrendanC
printfn handles recid correctly because you're using %A as the format specifier, which works with any and every type; I suspect it would fail if you used %d for the format specifier instead, which means that x.["PatientID"] is in fact not returning an int. Assuming you're using Visual Studio, can't you just mouse over rdict and look at the type in the tooltip? - ildjarn

2 Answers

1
votes

Assuming rdict is a Dictionary<int*(bool*bool), _> then to produce a ResizeArray<int> I propose:

let reclist =
    (ResizeArray<_>(), rdict.Keys)
    ||> Seq.fold(fun list (id,_) -> list.Add id; list)

Also, Dictionary<int*(bool*bool), _> strikes me as strange. Why not Dictionary<int*bool*bool, _>? I.e., why nest the bool pair as a second tuple? If you make this change, then one would call rdict.Add as so:

rdict.Add ((x.["PatientID"], true, true), ldiff)

And reclist would instead be:

let reclist =
    (ResizeArray<_>(), rdict.Keys)
    ||> Seq.fold(fun list (id,_,_) -> list.Add id; list)

EDIT: In your comment you mentioned the desire to build separate ResizeArrays based on different combinations of the two bools in the Dictionary key. Here's one thought on doing that:

let reclistOnlyA, reclistOnlyB, reclistBoth, reclistNeither =
    ((ResizeArray<_>(), ResizeArray<_>(), ResizeArray<_>(), ResizeArray<_>()), rdict.Keys)
    ||> Seq.fold(fun (a, b, both, neither as lists) (id, bools) ->
        (match bools with
         | true, false  -> a
         | false, true  -> b
         | true, true   -> both
         | false, false -> neither).Add id
        lists)
0
votes

For completeness and future reference I just wanted to post my results based on further testing. By boxing/unboxing I was able to successfully modify my previously posted code.

Hopefully this will of some use to someone else in the future.

    // Add initial value note the box call here
diff_dict.Add( (box x.["PatientID"],(true,true) ),ldiff) 


let reclist = new ResizeArray<int32>()
for KeyValue(k,v) in rdict do
    //printfn "Difference Dictionary - Key: %A; Value: %A; " k v 
    match k with
        // extract the result - note the 'unbox' call
        | (recid,(true,false)) ->  let n:int32 = unbox recid
                                   reclist.Add(n)