2 回答
TA贡献1785条经验 获得超8个赞
在Python中,在进行过程中改变(“更改”,“更新”)数据是一种常见的做法 - 就像你对列表所做的那样,在每一步都改变它。虽然即使在Python中也普遍不赞成它,但该语言本身使它变得非常容易,因此非常诱人。temp
在 F# 中,仍然可以更改数据,但语言使它变得困难。故意。好吧,这并不难 - 这只是几个额外的字符,但至少突变数据不是默认的。这是一种通常更好的方法,甚至Python社区现在也认识到了这一点。
相反,F# 方式(以及一般的函数方式)不是改变数据,而是通过转换旧数据来创建新数据。例如,函数的作用(其中“函数”是指“数学函数”)。
特别是,你的Python循环似乎正在做的是(1)过滤输入列表,然后(2)通过丢弃并只留下来转换(通常称为“映射”)每个元素,然后(3)排序。这可以用 F# 编写,如下所示:i[0]i[0]i[1]
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程序几乎相同,但含义却略有不同。而不是“做这个,然后做那个”(又名“命令式风格”),这个程序说“结果取决于以这种方式输入”(又名“功能风格”)。
TA贡献1804条经验 获得超3个赞
我能想到的从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# 中提到的,这个成语(即常用方法)是避免可变性,并且更喜欢内置的高阶函数(如过滤器和 map)来处理列表。
添加回答
举报