使用F#计算数字列表的笛卡尔乘积

时间:2009-06-01 18:09:26

标签: f#

我是f#

的新手

我试着计算一系列数字的笛卡尔积。我“借”了这个。

let xs = [1..99]
let ys = [1..99]
seq {for x in xs do for y in ys do yield x * y}

有更好或更优雅的方式吗?

加里

3 个答案:

答案 0 :(得分:9)

基于List模块提供的功能解决问题的另一个可能性是:

let xs = [1..99]
let ys = [1..99]
let zs = xs |> List.collect (fun x -> ys |> List.map (fun y -> x*y))

避免了对.concat的额外调用,也应该完成这项工作。

但我坚持你的解决方案。它应该是最可读的,是真正的对手。 (只是试着大声读出这些代码。你的完全可以理解,Noldorins或我的不是。)

答案 1 :(得分:7)

免责声明:我没有安装当前F#的机器,所以我无法测试我的代码。但是,基本上,如果您从Haskell窃取sequence,您可以将程序编写为

let cartesian = sequence >> List.map product

并将其作为

运行
cartesian [[1..99]; [1..99]]

以下是编写sequence的方法。它是您编写的序列表达式的通用版本。它只处理无限数量的列表:{ for x in xs do for y in ys do for z in zs ... yield [x;y;z;...] }

let rec sequence = function
  | [] -> Seq.singleton []
  | (l::ls) -> seq { for x in l do for xs in sequence ls do yield (x::xs) }
// also you'll need product to do the multiplication
let product = Seq.fold_left1 ( * )

然后你可以把你的程序写成

let cartesian xs ys = [xs; ys] |> sequence |> List.map product
// ... or one-argument, point-free style:
let cartesian' = sequence >> Seq.map product

您可能需要将某些Seq更改为List s。

但是,能够猜出非一般列表理解含义的人数可能比识别名称sequence要多得多,所以你可能更适合使用列表理解。但是,只要你想运行整个计算表达式列表,sequence就会派上用场。

答案 2 :(得分:2)

确实有一种稍微优雅的方式(至少在功能意义上)计算笛卡尔积,它使用List类中存在的函数。 (这里不需要涉及序列或循环,至少不是直接涉及。)

试试这个:

let xs = [1..99]
let ys = [1..99]
xs |> List.map(fun x -> ys |> List.map(fun y -> x * y)) |> List.concat

虽然稍微长一点,虽然风格更加实用,但看起来还是如此。