列表的笛卡尔半方

Cartesian half-square of a list

如何在 F# 中生成列表与自身的笛卡尔积的问题很常见,但我需要一些稍微不同的东西:结果平方的 half。也就是说,[1; 2; 3] -> [(1, 2), (1, 3), (2, 3)].

最明显的实现方式涉及带有整数索引的嵌套 for 循环,但在 F# 中最惯用的实现方式是什么?我不关心性能,只关心简单和优雅。

我不确定,但我想你想要这样的东西:

let pairs = function
   | [] -> [] 
   | (x::xs) -> List.map (fun x' -> (x,x')) xs

let rec hSquare xs =                        
   match xs with                           
   | [] -> []                              
   | (_::ys) -> pairs xs @ hSquare ys

使用 hSquare 例如:

> hSquare [1..3];;
val it : (int * int) list = [(1, 2); (1, 3); (2, 3)]
> hSquare [1..4];;
val it : (int * int) list = [(1, 2); (1, 3); (1, 4); (2, 3); (2, 4); (3, 4)]

其中包括您的示例

备注

  • 这肯定不是通常的笛卡尔积的一半(在你的情况下是 [(1,1);(1,2);(1,3);(2,1);(2,2);(2,3);(3,1);(3,2);(3,3)]
  • 我不关心性能、tailcalls 等等 - 你肯定可以改进这一点。
  • 我只是想知道您是否正在寻找这个并且它的评论太大了。

这是实现这些结果的基于 : one may also use a Sequence Expression 的强制性替代方案。

let c2 args = seq{
    let argsi = Seq.mapi (fun i x -> i, x) args 
    for (i, x) in argsi do
        for (j, y) in argsi do
            if i < j then yield (x, y) }

c2 [1..3]   // val it : seq<int * int> = seq [(1, 2); (1, 3); (2, 3)]