2010-12-22 31 views
4

我正在學習處理F#中的列表和元組,並且出現了一個問題。我有兩個名單:一個姓名,一個姓名,年齡。返回元組列表的第一個值


let namesToFind = [ "john", "andrea" ] 
let namesAndAges = [ ("john", 10); ("andrea", 15) ] 

我試圖創建將返回給namesToFind namesAndAges找到的第一個時代的功能。只是第一個。

到目前爲止,我有以下代碼返回整個元組(「john」,10)。


let findInList source target = 
      let itemFound = seq { for n in source do 
            yield target |> List.filter (fun (x,y) -> x = n) }         
           |> Seq.head  
      itemFound 

我試圖在返回語句中使用FST(),但它並不能編譯,給我「這樣的表達預計將有型‘A * B,而這裏的類型是('C *’d)名單「

感謝您的幫助!

回答

2

有很多的功能,可以使用的Collections.List模塊中。由於F#中沒有break或真實的return語句,因此使用某種搜索函數或編寫遞歸循環函數通常會更好。下面是一個例子:

let namesToFind = [ "john"; "andrea" ] 
let namesAndAges = [ "john", 10; "andrea", 15 ] 

let findInList source target = 
    List.pick (fun x -> List.tryFind (fun (y,_) -> x = y) target) source 

findInList namesToFind namesAndAges 

findInList函數是從Collections.List模塊由兩個函數組成。

  • 首先,我們有List.tryFind predicate list函數,它返回其給定的謂詞函數返回true的第一個項目。

    結果採用option類型的形式,可以使用兩個值:NoneSome(x)。它用於有時不會提供有用結果的功能。

    簽名是:tryFind : ('T -> bool) -> 'T list -> 'T option,其中'T是項目類型,('T -> bool)是謂詞函數類型。

    在這種情況下,它將通過target列表搜索列表,查找第一個元素(y)等於來自外部函數的變量x的元組。

  • 然後我們有List.pick mapper list函數,它將mapper函數應用到每個函數,直到第一個結果不是返回的None

    該函數不會返回option值,但是如果找不到項目則會拋出異常。還有一個option - 該函數名爲List.tryPick的變體。

    簽名是:pick : ('T -> 'U option) -> 'T list -> 'U,其中'T是項目類型,'U是的結果類型,而('T -> 'U option)是映射函數類型。

    在這種情況下,它將通過source -list,在target陣列中尋找匹配(通過List.tryFind),並且將在第一場比賽中停止。


如果你想明確地寫循環,這裏是它如何能期待:

let findInList source target = 
    let rec loop names = 
    match names with 
    | (name1::xs) -> // Look at the current item in the 
        // source list, and see if there are 
        // any matches in the target list. 
     let rec loop2 tuples = 
      match tuples with 
      | ((name2,age)::ys) -> // Look at the current tuple in 
            // the target list, and see if 
            // it matches the current item. 
       if name1 = name2 then 
       Some (name2, age) // Found a match! 
       else 
       loop2 ys   // Nothing yet; Continue looking. 
      | [] -> None   // No more items, return "nothing" 
     match loop2 target with   // Start the loop 
     | Some (name, age) -> (name, age) // Found a match! 
     | None -> loop rest    // Nothing yet; Continue looking. 
    | [] -> failwith "No name found" // No more items. 

    // Start the loop 
    loop source 

xsys是寫作列表或項目序列的常用方法)

3

首先讓我們看一下你的代碼和註釋的所有類:

let findInList source target = 
    let itemFound = 
     seq { 
      for n in source do 
       yield target |> List.filter (fun (x,y) -> x = n) }         
     |> Seq.head  
    itemFound 

聲明yield List.Filter ...意味着你創建列表的序列:seq<list<'a * 'b>>

語句Seq.head從您的列表序列中獲取第一個元素:list<'a * 'b>

因此,整個函數返回一個list<'a * 'b>,這顯然不是您的函數的正確類型。我想你打算寫這樣的事:

let findInList source target = 
    let itemFound = 
     target        // list<'a * 'b> 
     |> List.filter (fun (x,y) -> x = n) // list<'a * 'b> 
     |> Seq.head       // 'a * 'b 
    itemFound        // function returns 'a * 'b 

有很多方法可以得到你想要的結果。你的代碼已經有一半了。代替過濾的手,我建議使用內置的val Seq.find : (a' -> bool) -> seq<'a> -> 'a方法:

let findAge l name = l |> Seq.find (fun (a, b) -> a = name) |> snd 

或者你可以嘗試使用不同的數據結構像一個Map<'key, 'value>:如果您想將它寫

> let namesAndAges = [ ("john", 10); ("andrea", 15) ] |> Map.ofList;; 

val namesAndAges : Map<string,int> = map [("andrea", 15); ("john", 10)] 

> namesAndAges.["john"];; 
val it : int = 10 

手,然後用你的序列表達試試這個:

let findInList source target = 
    seq { 
     for (x, y) in source do 
      if x = target then 
       yield y} 
    |> Seq.head 
0

像fst一樣使用這個(下面)。這樣你可以訪問所有的值。

這是F#互動

let a = ((1,2), (3,4)); 
let b = snd (fst a);; 

//interactive output below. 
val a : (int * int) * (int * int) = ((1, 2), (3, 4)) 
val b : int = 2 
相關問題