F# 在Seq的所有对上测试对称函数的有效方法

F# 在Seq的所有对上测试对称函数的有效方法,f#,F#,假设我有一个像[a;b;c]这样的集合,我想用每个其他元素来测试每个元素 我可以像这样生成所有对: 设组合xs= Seq.allPairs xs |>顺序过滤乐趣x,y->x y |>序号:toList 组合[a;b;c] //[a,b;a,c;b,a;b,c;c,a;c,b] 但是对于我的测试,我总是知道f x y=f y x,因为f是对称的,所以我想减少测试的组合数: 设组合xs= Seq.allPairs xs |>Seq.filter fun x,y->x y&&x序号:toList 组

假设我有一个像[a;b;c]这样的集合,我想用每个其他元素来测试每个元素

我可以像这样生成所有对:

设组合xs= Seq.allPairs xs |>顺序过滤乐趣x,y->x y |>序号:toList 组合[a;b;c] //[a,b;a,c;b,a;b,c;c,a;c,b] 但是对于我的测试,我总是知道f x y=f y x,因为f是对称的,所以我想减少测试的组合数:

设组合xs= Seq.allPairs xs |>Seq.filter fun x,y->x y&&x序号:toList 组合[a;b;c] //[a,b;a,c;b,c] 但这是:

似乎不是生成测试用例的有效方法 需要x:comparison,我认为这是不必要的
我应该如何在F中实现这一点?

不知道如何提高效率-这看起来需要缓存已经生成的对,并根据它们在缓存中的存在进行筛选

Seq.allPairs的库实现遵循以下思路:

let allPairs source1 source2 =
    source1 |> Seq.collect (fun x -> source2 |> Seq.map (fun y -> x, y))
// val allPairs : source1:seq<'a> -> source2:seq<'b> -> seq<'a * 'b>
试验


不知道如何高效-看起来您需要缓存已经生成的对,并根据它们在缓存中的存在进行筛选

Seq.allPairs的库实现遵循以下思路:

let allPairs source1 source2 =
    source1 |> Seq.collect (fun x -> source2 |> Seq.map (fun y -> x, y))
// val allPairs : source1:seq<'a> -> source2:seq<'b> -> seq<'a * 'b>
试验


另一个假设所有元素都不同的解决方案使用位置作为标识:

设allSymmetricPairs x= 序号{ 设xs=Seq.toArray xs 对于i=0到Array.length xs-2 do 对于j=i+1到Array.length xs-1 do 收益率xs[i],xs[j] } 我们还可以预先分配阵列,如果您计划提取整个序列,则可能会更快:

let allSymmetricPairs xs =
  let xs = Seq.toArray xs
  let n = Array.length xs

  let result = Array.zeroCreate (n * (n - 1) / 2)

  let mutable k = 0

  for i = 0 to n - 2 do
    for j = i + 1 to n - 1 do
      result.[k] <- xs.[i], xs.[j]
      k <- k + 1

  result

另一个假设所有元素都不同的解决方案使用位置作为标识:

设allSymmetricPairs x= 序号{ 设xs=Seq.toArray xs 对于i=0到Array.length xs-2 do 对于j=i+1到Array.length xs-1 do 收益率xs[i],xs[j] } 我们还可以预先分配阵列,如果您计划提取整个序列,则可能会更快:

let allSymmetricPairs xs =
  let xs = Seq.toArray xs
  let n = Array.length xs

  let result = Array.zeroCreate (n * (n - 1) / 2)

  let mutable k = 0

  for i = 0 to n - 2 do
    for j = i + 1 to n - 1 do
      result.[k] <- xs.[i], xs.[j]
      k <- k + 1

  result
因为f是可交换的,所以获得所有组合的最简单方法是将每个项与列表的其余部分投影成一对

let rec combinations = function
| [] -> []
| x::xs -> (xs |> List.map (fun y -> (x, y))) @ (combinations xs)
我们不需要任何比较约束

let allPairs1 source1 source2 =
    let h = System.Collections.Generic.HashSet()
    source1 |> Seq.collect (fun x -> 
        source2 |> Seq.choose (fun y -> 
            if x = y || h.Contains (x, y) || h.Contains (y, x) then None
            else h.Add (x, y) |> ignore; Some (x, y) ) )
// val allPairs1 :
//     source1:seq<'a> -> source2:seq<'a> -> seq<'a * 'a> when 'a : equality
let xs = [1; 2; 3; 4;]
combinations xs // [(1, 2); (1, 3); (1, 4); (2, 3); (2, 4); (3, 4)]
使用@kaefer的方法检查结果:

combinations xs = (allPairs1 xs xs |> Seq.toList) // true
因为f是可交换的,所以获得所有组合的最简单方法是将每个项与列表的其余部分投影成一对

let rec combinations = function
| [] -> []
| x::xs -> (xs |> List.map (fun y -> (x, y))) @ (combinations xs)
我们不需要任何比较约束

let allPairs1 source1 source2 =
    let h = System.Collections.Generic.HashSet()
    source1 |> Seq.collect (fun x -> 
        source2 |> Seq.choose (fun y -> 
            if x = y || h.Contains (x, y) || h.Contains (y, x) then None
            else h.Add (x, y) |> ignore; Some (x, y) ) )
// val allPairs1 :
//     source1:seq<'a> -> source2:seq<'a> -> seq<'a * 'a> when 'a : equality
let xs = [1; 2; 3; 4;]
combinations xs // [(1, 2); (1, 3); (1, 4); (2, 3); (2, 4); (3, 4)]
使用@kaefer的方法检查结果:

combinations xs = (allPairs1 xs xs |> Seq.toList) // true