我正在使用OCaml,我有一个列表,我需要相互检查列表中的所有元素。该列表是单位列表,基本单位或派生单位。基本单位是m,s,g,派生单位是使用m,s,g的任何单位,如kg,min,ft,lb等。
所以一个示例列表将是[lb;英尺;米]。此列表无效,因为ft和m共享相同的基本单位:m。更清楚[lb;公斤; s]将无效,因为lb和kg共享相同的基本单位:m。然而[ft; S; m]完全有效。这些基本单位转换保存在哈希中以供查找。
我的问题是如何相互检查所有单位。我尝试过使用褶皱,但它会让我的头部受伤。任何人都可以帮助我吗?
答案 0 :(得分:2)
具有二次复杂度的简单解决方案:
(* [check_pair] should return [false] if check fails *)
let rec check_each_pair check_pair = function
| [] -> true
| hd1 :: rest ->
let rec check_rest = function
| [] -> true
| hd2 :: rest -> check_pair hd1 hd2 && check_rest rest
in
check_rest rest && check_each_pair check_pair rest
注意内部check_rest
仅检查列表中每个元素的谓词。那是List.for_all
。
let rec check_each_pair check_pair = function
| [] -> true
| hd1 :: rest ->
List.for_all (check_pair hd1) rest && check_each_pair check_pair rest
你可以去组合疯狂,也可以实现check_each_pair
作为对递归组合的调用,但这不是直接的(你需要以某种方式累积rest
,所以折叠,但是你想要快捷方式失败 - 早期语义......)我没有看到任何优势。
答案 1 :(得分:1)
一个简单的解决方案是首先从列表中创建所有对的列表(通过使用列表中的cartesian product)并稍后检查对列表中的条件:
let cartesian xs ys =
List.concat (List.map (fun x -> List.map (fun y -> (x, y)) ys) xs)
let haveDifferentBases(x, x') =
(* check whether they have different base units *)
let check_all_pairs xs =
List.for_all haveDifferentBases (cartesian xs xs)