f# - 在 Seq 的所有配对上测试对称函数的有效方法
问题描述
假设我有一个类似的集合,[ "a"; "b"; "c" ]
并且我想针对每个其他元素测试每个元素。
我可以像这样生成所有对:
let combinations xs =
Seq.allPairs xs xs
|> Seq.filter (fun (x, y) -> x <> y)
|> Seq.toList
combinations [ "a"; "b"; "c" ]
// [("a", "b"); ("a", "c"); ("b", "a"); ("b", "c"); ("c", "a"); ("c", "b")]
但是对于我的测试,我总是知道f x y = f y x
(因为f
是对称的),所以我想修剪测试的组合数量:
let combinations xs =
Seq.allPairs xs xs
|> Seq.filter (fun (x, y) -> x <> y && x < y)
|> Seq.toList
combinations [ "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<'a>
并引入equality
约束。
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
测试
allPairs1 [1..3] [2..4] |> Seq.toList
// val it : (int * int) list = [(1, 2); (1, 3); (1, 4); (2, 3); (2, 4); (3, 4)]
推荐阅读
- javascript - 如果我想在电子表格的所有工作表中获得相同的特定列集,Google Sheets API 的 A1 表示法是什么?
- c# - CS0433 类型存在于两个组件中
- android - Android MotionLayout autoTransition 在 beta7 中不起作用
- z3 - 将 Z3 转换为 CVC4 的问题
- reactjs - react-router 从 3.x 升级到 5.x
- c# - 我应该将 Protobuf 与 Unity(或 protobu-net)一起使用吗?如果是这样,怎么做?
- c# - 检查数据的值是否为空c#
- c# - 给定基本读取方法,如何读取自定义类的数据包?
- javascript - 使用具有重叠元素的 iframe 获取用户的鼠标坐标时出现问题
- python - 有没有办法在 Pandas 中按一组列值进行唯一分组?