返回元组列表的第一个值

时间:2010-12-22 20:37:58

标签: list f# tuples

我正在学习处理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)列表”

感谢您的帮助!

3 个答案:

答案 0 :(得分: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

如果您想手动编写,请尝试使用您的seq表达式:

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

答案 1 :(得分: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

    < / LI>
  • 然后我们有List.pick mapper list函数,它将mapper - 函数应用于每个函数,直到返回的第一个结果不是None

    此函数不会返回option值,但如果找不到任何项,则会抛出异常。此函数的option变体名为List.tryPick

    签名为:pick : ('T -> 'U option) -> 'T list -> 'U,其中'T为项类型,'U为结果类型,('T -> 'U option)为映射函数类型。

    在这种情况下,它将遍历source - 列表,在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是编写列表或项目序列的常用方法。

答案 2 :(得分:0)

像fst一样使用这个(下面)。这样您就可以访问所有值。

这是来自F#interactive

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