2009-06-01 125 views
6

我是f新手#用F#计算笛卡尔乘积列表的乘积

我试着计算笛卡尔乘积的列表中的乘积。我“借”这个。

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

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

加里

+0

相关问题在这里:http://stackoverflow.com/questions/482866/f-cross-product-of-two-lists – Benjol 2009-06-02 06:56:56

回答

9

另一个possibiltiy基于列表模块提供的是功能来解决这个问题:

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

避免了额外要求,以.concat,也应该做的工作。

但我会坚持你的解决方案。它应该是最可读的,它是一个真正的匹配者。 (只是试着大声地读出代码,你完全可以理解,而Noldorins或我的不是)

2

的确有一个稍微更优雅的方式(至少在功能意义上)来计算笛卡尔乘积,其使用存在于List类内的功能。 (有没有必要让序列或环这里,至少不是直接)

试试这个:

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

稍长无可否认,尽管功能更强大的风格,它似乎。

+1

其实在问题中的代码比你的代码更接近列表理解,在我看来。你的更像是一个列表理解的desugared版本。 – 2009-06-01 21:10:47

+0

是的,我并不是指列表解析实际上 - 我不确定它有一个特殊的名称,但我的意思是List。*函数。 – Noldorin 2009-06-02 03:19:54

+0

您可以详细说明“无需涉及序列”的含义吗,我不明白在Seq.map上使用List.map会带来哪些好处? – ninegrid 2009-06-02 21:40:01

7

声明:我没有安装当前F#的机器,所以我无法测试我的代码。基本上,不过,如果你从哈斯克尔偷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 s到List秒。

但是,能够猜出非一般列表理解含义的人数可能比识别名称sequence多很多,所以你可能比列表理解更好。 sequence随时可以运行整个计算表达式列表。