繁体   English   中英

从 Python 转换为 F# 递归函数?

[英]Converting from Python to F# recursive function?

我正在尝试将此 Python 代码转换为 F# 而不使用不可变变量或List.map 我仍然是这个新手。

def findMatches(s,l):
    temp=[]
    for i in l:
        if i[0]==s:
            temp.append(i[1])
    temp.sort()
    return temp

l=findMatches("A",[("A",5),("AA",9),("BB",6),("A",0)])
print(l)

我已经开始:

let findMatches s l =
    for e1, e2 in list do
        if e1 = s then ...

如果我朝着正确的方向前进或下一步要去哪里,则并非完全如此。

在 Python 中,在执行过程中改变(“更改”、“更新”)数据是一种常见的做法 - 就像您正在处理temp列表一样,在每一步都改变它。 尽管即使在 Python 中它也普遍不受欢迎,但语言本身使它非常容易,因此非常诱人。

在 F# 中,仍然可以改变数据,但语言使它变得困难。 故意。 好了,没有那么难-它只是一些额外的字符, -但至少变异的数据是不是默认。 这通常是一种更好的方法,甚至 Python 社区现在也承认这一点。

相反,F# 方式(以及一般来说,功能方式)不是改变数据,而是通过转换旧数据来创建新数据。 就像函数的作用一样(“函数”我的意思是“数学函数”)。

特别是,您的 Python 循环似乎在做的是 (1) 通过i[0]过滤输入列表,然后 (2) 通过丢弃i[0]并只留下i[1]转换(通常称为“映射”)每个元素i[1] ,然后(3)排序。 这可以用 F# 写成这样:

let findMatches s l =
    l
    |> List.filter (fun (e1, _) -> e1 == s)  // filtering
    |> List.map (fun (_, e2) -> e2)          // mapping
    |> List.sort

该程序不是通过重复变异来“构建”列表,而是通过三次转换输入列表来创建结果列表:过滤,然后映射,然后排序。 另一个需要注意的是,转换本身是由较小的部分构建的:整个列表的转换是通过转换单个元素的转换来实现的。

对于像这样的简单情况(排序除外),F# 还提供了特殊的语法——所谓的“列表推导式”。 它是语法糖,它在幕后执行与上述类似的转换,但语法(可以说)更具可读性:

let findMatches s l =
    [ for e1, e2 in l do
        if e1 == s then yield e2
    ]
    |> List.sort

请注意,尽管这看起来与您的 Python 程序几乎相同,但含义却略有不同。 这个程序不是“做这个,然后做那个”(又名“命令式”),这个程序说“结果以这种方式取决于输入”(又名“功能式”)。

我能想到的从 Python 示例代码到 F# 的最直接映射:

// I tend to specify the signatures of methods as I find it helpful
let findMatches (s : 'K) (l : seq<'K*'V>): seq<'V> =
  // ResizeArray is an alias for System.Collections.Generic.List<_>
  let temp = ResizeArray ()
  for e1, e2 in l do
    if e1 = s then
      temp.Add e2
  temp.Sort ()
  // F# don't do implicit upcasts like C# so an explicit upcast from
  //  ResizeArray to seq
  upcast temp

正如 Fyodor 在 F# 中提到的,习惯用法(即常用方法)是为了避免可变性,并且更喜欢内置的高阶函数(如过滤器和映射)来处理列表。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM