返回元组列表的第一个值

发布于 2024-10-08 13:40:16 字数 687 浏览 0 评论 0 原文

我正在学习处理 F# 中的列表和元组,但出现了一个问题。我有两份清单:一份是姓名,另一份是姓名、年龄。


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

我正在尝试创建一个函数,该函数将返回在给定名称ToFind 的名称AndAges 中找到的第一个年龄。只是第一个。

到目前为止,我有以下代码,它返回整个元组(“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) 列表”

感谢您的帮助!

I'm learning to deal with Lists and Tuples in F# and a problem came up. I have two lists: one of names and one with names,ages.


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

I'm trying to create a function that will return the first age found in namesAndAges given namesToFind. Just the first.

So far I have the following code which returns the entire tuple ("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

I tried using fst() in the returning statement but it does not compile and gives me "This expression was expected to have type 'a * 'b but here has type ('c * 'd) list"

Thanks for any help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

找个人就嫁了吧 2024-10-15 13:40:16

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 谓词列表 函数,它返回给定谓词函数返回 true 的第一个项目。

    结果采用 option 类型的形式,可以采用两个值:NoneSome(x)。它用于有时不会给出有用结果的函数。

    签名是: tryFind : ('T -> bool) -> 'T 列表 -> 'T option,其中 'T 是项目类型,('T -> bool) 是谓词函数类型。

    在这种情况下,它将搜索 target 列表,查找第一个元素 (y) 等于变量 x 的元组外部函数。

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

    此函数不会返回 option 值,但如果未找到项目,则会抛出异常。该函数还有一个名为 List.tryPickoption 变体。

    签名是: pick : ('T -> 'U 选项) -> 'T 列表 -> 'U,其中 'T 是项目类型,'U 是结果类型,('T -> 'U 选项) 是映射函数类型。

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

There are lots of functions in the Collections.List module that can be used. Since there are no break or a real return statement in F#, it is often better to use some search function, or write a recursive loop-function. Here is an example:

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

The findInList function is composed of two functions from the Collections.List module.

  • First we have the List.tryFind predicate list function, which returns the first item for which the given predicate function returns true.

    The result is in the form of an option type, which can take two values: None and Some(x). It is used for functions that sometimes give no useful result.

    The signature is: tryFind : ('T -> bool) -> 'T list -> 'T option, where 'T is the item type, and ('T -> bool) is the predicate function type.

    In this case it will search trough the target list, looking for tuples where the first element (y) equals the variable x from the outer function.

  • Then we have the List.pick mapper list function, which applies the mapper-function to each one, until the first result that is not None, which is returned.

    This function will not return an option value, but will instead throw an exception if no item is found. There is also an option-variant of this function named List.tryPick.

    The signature is: pick : ('T -> 'U option) -> 'T list -> 'U, where 'T is the item type, 'U is the result type, and ('T -> 'U option) is the mapping function type.

    In this case it will go through the source-list, looking for matches in the target array (via List.tryFind) for each one, and will stop at the first match.


If you want to write the loops explicitly, here is how it could look:

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

(xs and ys are common ways of writing lists or sequences of items)

世界等同你 2024-10-15 13:40:16

首先让我们看一下您的代码并注释所有类型:

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 ;>

语句 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

First let's look at your code and annotate all the types:

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

The statement yield List.Filter ... means you're creating a sequence of lists: seq<list<'a * 'b>>.

The statement Seq.head takes the first element from your sequence of lists: list<'a * 'b>.

So the whole function returns a list<'a * 'b>, which is obviously not the right type for your function. I think you intended to write something like this:

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

There are lots of ways you can get the results you want. Your code is already half way there. In place of filtering by hand, I recommend using the built in val Seq.find : (a' -> bool) -> seq<'a> -> 'a method:

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

Or you can try using a different data structure like a 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

If you want to write it by hand, then try this with your seq expression:

let findInList source target = 
    seq {
        for (x, y) in source do
            if x = target then
                yield y}
    |> Seq.head
烧了回忆取暖 2024-10-15 13:40:16

就像首先使用这个(如下)。这样您就可以访问所有值。

这是来自 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

Like fst use this(below) . This way you can access all the values.

This is from 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文