任何人都可以为SML中的一个函数提供任何建议,它将获取2个列表并返回它们的XOR,这样如果你有列表[a,b,c,d],[c,d,e, f]函数返回[a,b,e,f]?
我尝试用2个函数来做,但即使这样也无法正常工作。
fun del(nil,L2) = nil
|del(x::xs,L2)=
if (List.find (fn y => y = x) L2) <> (SOME x) then
del(xs, L2) @ [x]
else
del(xs, L2);
fun xor(L3,L4) =
rev(del(L3,L4)) @ rev(del(L4,L3));
答案 0 :(得分:2)
你的尝试几乎是正确的,除了fn x => x = x
没有意义,因为它总是返回true。我想你想要fn y => y = x
。
其他一些评论:
您可以将List.find
的使用替换为更接近您想要的List.filter
。
不要为递归步骤执行del(xs,L) @ [x]
。附加到列表末尾的成本与第一个列表的长度成线性关系,因此如果您在每个步骤中执行此操作,则您的函数将具有二次运行时。请改为x :: del(xs,L)
,这也允许您最后删除列表反转。
这里所谓的“异或”通常称为对称差异,至少对于类似于集合的结构。
答案 1 :(得分:1)
最简单的方法是从每个列表中过滤掉重复项,然后连接两个结果列表。使用List.filter,您可以删除作为另一个列表的成员(List.exists)的任何元素。
然而,这是非常低效的,下面的代码更像是在现实生活中如何不这样做的一个例子,尽管它在“功能上”很好看:)
fun symDiff a b =
let
fun diff xs ys =
List.filter (fn x => not (List.exists ( fn y => x = y) ys)) xs
val a' = diff a b
val b' = diff b a
in
a' @ b'
end
这应该是一个更好的解决方案,仍然保持简单。它使用SML / NJ特定的ListMergeSort模块对组合列表a @ b
进行排序。
fun symDiff1 a b =
let
val ab' = ListMergeSort.sort op> (a @ b)
(* Remove elements if they occur more than once. Flag indicates whether x
should be removed when no further matches are found *)
fun symDif' (x :: y :: xs) flag =
(case (x = y, flag) of
(* Element is not flagged for removal, so keep it *)
(false, false) => x :: symDif' (y :: xs) false
(* Reset the flag and remove x as it was marked for removal *)
| (false, true) => symDif' (y::xs) false
(* Remove y and flag x for removal if it wasn't already *)
| (true, _) => symDif' (x::xs) true)
| symDif' xs _ = xs
in
symDif' ab' false
end
然而,这仍然是一种愚蠢的行为。由于排序功能遍历组合列表中的所有元素,因此它也应该是“负责”删除重复项的元素。