Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
家庭作业:Lisp项目在列表中出现多次_Lisp_Duplicates - Fatal编程技术网

家庭作业:Lisp项目在列表中出现多次

家庭作业:Lisp项目在列表中出现多次,lisp,duplicates,Lisp,Duplicates,给定一个列表,我试图返回一个新的列表,其中只包含在我作为参数收到的第一个列表中多次出现的项目 我已经做了以下工作: (defun myf (lista) (if (endp lista) nil (if (member (first lista) (rest lista)) (append (list (first lista)) (myf (rest lista))) (myf (rest lista))))) 如果我运行

给定一个列表,我试图返回一个新的列表,其中只包含在我作为参数收到的第一个列表中多次出现的项目

我已经做了以下工作:

(defun myf (lista)
  (if (endp lista)
      nil
      (if (member (first lista) (rest lista))
          (append (list (first lista)) (myf (rest lista)))
          (myf (rest lista))))) 
如果我运行以下命令:
(myf'(aabbc))
,它将返回
(aab)

如何使其仅返回一次项(即,不具有双“A”)?

问题似乎在于您正在检查列表的第一个元素是否位于列表的尾部,并将其附加到结果列表中。当您看到A的第二个实例时,就会出现问题,选中该实例时表示是,它位于尾部,因为列表中有A的第三个实例。如果输入列表有4个A,那么它将返回其中的3个


所以要解决这个问题,需要检查A是否已经是结果列表的成员。也就是说,如果first lista不是列表的成员,则将first lista附加到列表。

问题似乎是,在附加到输出列表之前,您没有检查该元素是否存在于该列表中。

一旦发现一个字母多次出现在列表中,您就不需要再次检查它,因此,在列表的其余部分中不需要它。所以你可以修改剩下的列表


注意:这个答案故意有些含糊,因为它是针对家庭作业和所有内容的。:)

现在,对于列表中的每个元素,如果该元素未包含在列表的其余部分中,则将其添加到结果中


为了得到您显然想要的结果,如果列表中的每个元素尚未包含在结果中,您可以将其添加到结果中。

Vincent、Gishu和Jerry暗示,在添加到结果列表之前,您需要检查该项是否已在结果列表中,而Derek暗示,当您看到某个项目重复时,可以修改原始列表

阅读此处的函数
邻接
删除
的文档:

这是一个非常有用的参考资料,将其添加到书签中

这两个函数不修改其参数,而是将结果作为新列表返回。还有其他函数可以修改它们的参数,因此可能更有效,但在这一点上,也许您不必担心它们

好的,我希望在我写这篇文章的时候你已经明白了。如果没有,继续尝试,那是你真正学习的唯一方法

现在我想和大家谈谈另一种方法,那就是通过递归调用来传递结果

我们的函数
repeated
只会调用一个helper函数
repeatedr
,该函数将执行实际工作,并向其传递一个初始空结果
'()

现在让我们定义helper函数,它接收两个参数:用于搜索重复项的列表和用于累积重复项的结果列表

(defun repeatedr (lst result)
  (if (null lst)
    result
    (if (member (first lst) (rest lst))
      (repeatedr (rest lst) (adjoin (first lst) result))
      (repeatedr (rest lst) result))))
当条件
(member(first lst)(rest lst))
成立时,我们将将第一项邻接到
结果
,邻接的结果将作为第二个参数传递给递归调用;否则,我们只将
结果按原样传递给递归调用

当列表最终为空时(如果(null lst)
,我们将返回
结果

> (repeated '(a a b a b c))
(B A)
请注意,结果是
(ba)
,可能您希望它是
(ab)
。尝试用笔和纸跟踪递归调用的执行情况以及每次调用时的参数值,这将是一个很好的练习,您必须使用
adjoin
来了解其行为。如果您想得到相反的结果,可以像这样修改函数:

(defun repeatedr (lst result)
  (if (null lst)
    (reverse result)
    (if (member (first lst) (rest lst))
      (repeatedr (rest lst) (adjoin (first lst) result))
      (repeatedr (rest lst) result))))
(defun repeatedr (lst result)
  (if (null lst)
    result
    (if (member (first lst) (rest lst))
      (repeatedr (remove (first lst) lst) (cons (first lst) result))
      (repeatedr (rest lst) result))))
这将在递归结束时反转结果

现在,关于在继续之前从列表中删除重复元素的建议呢?我们可以这样编写函数:

(defun repeatedr (lst result)
  (if (null lst)
    (reverse result)
    (if (member (first lst) (rest lst))
      (repeatedr (rest lst) (adjoin (first lst) result))
      (repeatedr (rest lst) result))))
(defun repeatedr (lst result)
  (if (null lst)
    result
    (if (member (first lst) (rest lst))
      (repeatedr (remove (first lst) lst) (cons (first lst) result))
      (repeatedr (rest lst) result))))
尝试在REPL处玩
remove

> (remove 'a '(a b c d a e f b a d))
(B C D E F B D)
请注意,我们不再与结果相邻,而是使用
(cons(first lst)result)
cons
adjoin
创建一个新的“cons cell”,但adjoin仅在列表中不存在时才会添加值


希望这能给您带来一些乐趣。

如果订单不是一个问题,那么您也可以:

(取消我的乐趣无订单(lst)
(循环用于lst上的(项目休息)
当(=(计数项目剩余)0)
收集物品)

在这里,我们迭代一个列表,将其放入正在迭代的当前项和其他待检查项中。when子句确定我们收集该项的情况。

是的,这就是我不知道的,如何在不使用变量(即set、let等)的情况下检查它选择A作为副本后,将A的所有实例从“rest of lista”中删除如何?如果表单更好地转换为COND,请链接。谢谢您的精彩解释