两个列表的交叉产品

Ben*_*jol 15 .net f#

乱用List模块的"扩展功能".(我花了很长时间开发'mapfold' - 它将一个累加器像fold折叠,但是使用它作为参数来创建像map这样的新值 - 然后发现那是什么List.scan_left)

为了生成测试数据,我需要做两个列表的交叉产品,这就是我提出的:

///Perform cross product of two lists, return tuple
let crossproduct l1 l2 =
    let product lst v2 = List.map (fun v1 -> (v1, v2)) lst
    List.map_concat (product l1) l2
Run Code Online (Sandbox Code Playgroud)

这有什么好处,还是有更好的方法来做到这一点?

同样的问题:

///Perform cross product of three lists, return tuple
let crossproduct3 l1 l2 l3 =
    let tuplelist = crossproduct l1 l2 //not sure this is the best way...
    let product3 lst2 v3 = List.map (fun (v1, v2) -> (v1, v2, v3)) lst2
    List.map_concat (product3 tuplelist) l3
Run Code Online (Sandbox Code Playgroud)

Tom*_*cek 25

另一种选择是使用F#"序列表达式"并写下这样的东西:

let crossproduct l1 l2 =
  seq { for el1 in l1 do
          for el2 in l2 do
            yield el1, el2 };;
Run Code Online (Sandbox Code Playgroud)

(实际上,它与你所写的内容几乎相同,因为'for .. in .. do'在序列表达式中可以被视为map_concat).这适用于(懒惰)序列,但如果你想使用列表,你只需将代码包装在[...]内而不是seq {...}中.


Col*_*nic 6

从 F# 4.0 开始,您可以使用List.allPairs来给出两个列表的笛卡尔积。

如果您有两个以上的列表,请参阅如何在 F# 中计算 n 个序列的笛卡尔积?


Ben*_*jol 5

刚刚使用计算表达式遇到了一个相当优雅的解决方案:

type Product () =
  member this.Bind (l,f) = List.collect f l    
  member this.Return n = [n]

let enumeratedPizzas = 
  Product() {
    let! x = ["New York";"Chicago"]
    let! y = ["Pepperoni";"Sausage"]
    let! z = ["Cheese";"Double Cheese"]
    return x,y,z
  }
Run Code Online (Sandbox Code Playgroud)

Techneilogy 提供,从fssnip.net复制,点击链接查看注释代码。

  • 我遇到了这个相当古老的问题 - 值得注意的是,这与序列表达式使用的模式完全相同,只是语法更难看。我在 http://www.cl.cam.ac.uk/~tp322/drafts/notations.html 中写了(很多)关于不同句法选项的更多信息 (2认同)