F# 有没有更有效或更惯用的方法来引用值表

F# Is there a more effective or idiomatic way to reference a table of values

提问人:noobIam 提问时间:10/4/2023 最后编辑:JFMRnoobIam 更新时间:10/6/2023 访问量:99

问:

如果有一个不变的值表,函数将需要偶尔从中查找 ,比如一张 4x5 的桌子,其中列是水果,行是鸟。我想要一个函数,给定一个水果和一只鸟在表中查找正确的值。

以下是我是如何做到的,我想知道是否有更惯用的 F# 方式?还是更简单或更有效的方法?

let getter bird fruit =
    let listoflists =
    [ "Eagle", [ "Cherry", 1.1; "Pear", 1.4; "Orange", 1.2; "Apple", 1.1; "Banana", 1.0 ]
      "Hawk", [ "Cherry", 1.1; "Pear", 1.4; "Orange", 1.2; "Apple", 1.1; "Banana", 1.0 ]
      "Turkey", [ "Cherry", 1.1; "Pear", 1.1; "Orange", 1.1; "Apple", 1.0; "Banana", 1.0 ]
      "Chicken", [ "Cherry", 1.1; "Pear", 1.1; "Orange", 1.1; "Apple", 1.0; "Banana", 1.0 ] ]

    let lookup = [ for x, y in listoflists -> x, y |> Map.ofList ] |> Map.ofList
    lookup.[bird].[fruit]
f# 嵌套列表

评论


答:

2赞 Martin521 10/4/2023 #1

我认为代码很好,但效率低下,因为列表和地图在每次调用中都会重新构建。如果列表不是太大,并且函数不经常被调用,这可能是完全可以的。

如果效率是一个问题,则必须在函数之外创建映射。

评论

0赞 noobIam 10/5/2023
谢谢,我希望从这篇文章中获得更有效的做事方式的想法。由于我是一个菜鸟程序员,我敢肯定我以笨拙的方式做了很多事情。
3赞 Brian Berns 10/4/2023 #2

正如@Martin521提到的,这是低效的,因为您每次都在重建地图。我建议使用构造函数(而不是 )在 getter 之外只构建一次结构:MapMap.ofList

let lookup =
    Map [
        "Eagle", Map [ "Cherry", 1.1; "Pear", 1.4; "Orange", 1.2; "Apple", 1.1; "Banana", 1.0 ]
        "Hawk", Map [ "Cherry", 1.1; "Pear", 1.4; "Orange", 1.2; "Apple", 1.1; "Banana", 1.0 ]
        "Turkey", Map [ "Cherry", 1.1; "Pear", 1.1; "Orange", 1.1; "Apple", 1.0; "Banana", 1.0 ]
        "Chicken", Map [ "Cherry", 1.1; "Pear", 1.1; "Orange", 1.1; "Apple", 1.0; "Banana", 1.0 ]
    ]

let getter bird fruit =
    lookup.[bird].[fruit]

由于这是行和列的表,我也会考虑使用 Deedle 数据框而不是地图地图。

评论

0赞 noobIam 10/5/2023
谢谢你,从我昨天的谷歌搜索中,无论出于何种原因,我发现的每个地图示例都从未提到过原始地图构造函数,所以我不知道这是一回事。我的代码将有一堆我需要从中提取的小表,但它们都非常小,就像问题中的 4x5 表一样,它们都不需要转换或更改,所以我想我应该像这样对它们进行硬编码。
0赞 Brian Berns 10/5/2023
是的,Map 构造函数并没有像文档中应该的那样调用,但它非常方便。请注意,有一个名为“的函数将执行大致相同的操作,但会创建一个而不是映射。dictIDictionary
1赞 Tomas Petricek 10/4/2023 #3

我认为基于地图的解决方案在这样的简单情况下效果很好。但是,如果您的用例更复杂(并且您还需要加载或转换数据),Brian 提到的 Deedle 库可能会很有用。它内置了您需要的那种有效查找:

#r "nuget: Deedle"
open Deedle

let df = 
  frame
    [ "Eagle" => series [ "Cherry", 1.1; "Pear", 1.4; "Orange", 1.2; "Apple", 1.1; "Banana", 1.0 ]
      "Hawk" => series [ "Cherry", 1.1; "Pear", 1.4; "Orange", 1.2; "Apple", 1.1; "Banana", 1.0 ]
      "Turkey" => series [ "Cherry", 1.1; "Pear", 1.1; "Orange", 1.1; "Apple", 1.0; "Banana", 1.0 ]
      "Chicken" => series [ "Cherry", 1.1; "Pear", 1.1; "Orange", 1.1; "Apple", 1.0; "Banana", 1.0 ] ]

let getter bird fruit =
  df.[bird, fruit]

getter "Eagle" "Pear"