2016-05-12 6 views
3

Ich möchte Tupel in einem Satz von ersten zwei Werte finden und dritten Wert des Tupel (oder keine, wenn nichts gefunden) zurückgeben. Ich woluld so etwas wie:Get Element aus Menge von Tupel in F #

type Point = (int * int * int) 
type Path = Set<Point> 

let f (x:int) (y:int) (p:Path) : int Option = 
    if Set.exists ((=) (x, y, _z)) p 
    then Some _z 
    else None 

let p:Path = Set.ofList [ (0, 1, 100); (1, 1, 500); (1, 2, 50); ] 

f 1 2 p 

Aber dies nicht funktioniert, weil offenbar, Pattern-Matching in Ausdrücken nicht erlaubt ist. Was ist der richtige Ansatz? Vielen Dank.

+0

Was ist falsch an einem zweistufigen Ansatz? –

+1

Was ist '_z' ..? – ildjarn

+0

@John Palmer Was meinst du? Finden Sie zuerst das Tupel und zweitens den Wert daraus? – Feofilakt

Antwort

5

Sie können die Set zur Liste konvertieren und List.tryFind zu verwenden

let f (x:int) (y:int) (p:Path) : int Option = 
    Set.toList p 
    |> List.tryFind (fun (px, py, _) -> x = px && y = py) 
    |> Option.map (fun (_, _, pz) -> pz) 
+0

Ich denke, das ist die einfachste Lösung – Feofilakt

1

Ist das, was Sie tun möchten?

let f (x:int) (y:int) (p:Path) : int Option = 
    match p |> Set.filter (fun (x', y', _) -> x' = x && y' = y) |> Set.toList with 
    | [(_, _, z)] -> Some z 
    | [] -> None 
    | _ -> failwith "More than one point was found!" 

Beispiel:

> let p:Path = Set.ofList [ (0, 1, 100); (1, 1, 500); (1, 2, 50); ];; 

val p : Path = set [(0, 1, 100); (1, 1, 500); (1, 2, 50)] 

> f 1 2 p;; 
val it : Option<int> = Some 50 
+0

Leider ist dies O (N) auf einer geordneten Sammlung; es könnte O (logN) sein, wenn 'Set' eine' lowerBound' Funktion hatte ... – ildjarn

2

Dies ist eine ziemlich saubere Lösung ist mit fold

let f x y p = Set.fold (function |None -> (fun (x_,y_,z) -> if x=x_ && y=y_ then Some z else None) |f ->fun _ -> f) None p 
+0

Das funktioniert nicht. Es überprüft effektiv nur das letzte Element des Satzes. f 0 1 p returns None – hvester

+0

@hvester - woops hat versehentlich die alte Version eingefügt –

5

Iterieren auf hvester Antwort:

let f (x:int) (y:int) (p:Path) : int Option = 
    p |> Seq.tryPick (function 
         | x', y', z' when x = x' && y = y' -> Some z' 
         | _ -> None) 

tryPick im Wesentlichen doe s Finde und kartiere in einem Schritt.