从Python到F#递归函数的转换?

2024-04-26 14:13:55 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图将这段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 ...

如果我走的方向正确,或者下一步该去哪里,就不完全是这样


Tags: 代码inmapforreturnifdefsort
2条回答

从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#中提到的,习惯用法(即常用方法)是避免易变性,并且更喜欢内置的高阶函数(如过滤器和映射)而不是进程列表

在Python中,一种常见的做法是在执行过程中对数据进行变异(“更改”、“更新”),就像处理temp列表一样,在每一步都对其进行变异。虽然即使在Python中也普遍不赞成它,但该语言本身使它非常简单,因此非常诱人

在F#中,变异数据仍然是可能的,但语言让它变得困难。故意地嗯,这不是很难的-只是几个额外的字符-但至少变异数据不是默认的。这通常是一种更好的方法,就连Python社区现在也认识到了这一点

相反,F#方式(以及通常的功能方式)不是变异数据,而是通过转换旧数据来创建新数据。在中,函数是做什么的(这里的“函数”指的是“数学函数”)

特别是,Python循环似乎正在做的是:(1)通过i[0]过滤输入列表,然后(2)通过丢弃i[0]并只留下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程序几乎相同,但其含义却略有不同。这个程序不是“做这个,然后做那个”(又名“命令式风格”),而是说“结果以这种方式取决于输入”(又名“功能性风格”)

相关问题 更多 >