SML函数用2个返回XOR的列表---固定

时间:2013-01-19 00:52:57

标签: list sml xor

任何人都可以为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));

2 个答案:

答案 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

然而,这仍然是一种愚蠢的行为。由于排序功能遍历组合列表中的所有元素,因此它也应该是“负责”删除重复项的元素。