F# 在Seq的所有对上测试对称函数的有效方法
假设我有一个像[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&&xF# 在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 组
我应该如何在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