【问题标题】:Searching for an element within lists of lists without MAPCAR在没有 MAPCAR 的列表列表中搜索元素
【发布时间】:2018-04-05 10:09:56
【问题描述】:

我尝试编写一个程序,用T 替换列表L 中元素A 的所有实例,用NIL 替换不同的元素。赌注是不要使用mapcar

这是我之前所做的。我将所有TNIL 存储在一个新列表POS 中,然后返回POS

(defun SRC (A L) 
  (defun _SRC (A L POS) 
    (COND ((NOT (EQUAL (CAR L) NIL))
           (_SRC A (CDR L) (APPEND POS (LIST (EQUAL A (CAR L)))))) 
          ((EQUAL (CAR L) NIL)
           (APPEND POS (LIST (EQUAL A NIL))))
          (T POS)))
  (CDR (_SRC A L (LIST NIL))))

当前行为: 该程序运行良好,除了搜索 NIL 本身时,但这里不关心这种特殊情况。

我的代码的几个示例运行:-

   (SRC 'g '(a g g o t g))
> (nil t t nil nil t)

在列表中搜索NIL 时:-

   (SRC nil '(t a t nil nil))
> (nil nil nil t)

在这种特殊情况下,我们的程序在找到列表中的第一个 NIL 时结束,对于其他搜索,程序可以正常工作。所以我尝试添加在列表列表中搜索的功能。

我在没有mapcar的列表列表中搜索的更新代码:

(defun SRC (A L) 
 (defun _SRC (A L POS) 
   (COND ((LISTP (CAR L))
          (APPEND POS (LIST (SRC A (CAR L))))) 
         ((NOT (EQUAL (CAR L) NIL)) 
          (_SRC A (CDR L) (APPEND POS (LIST (EQUAL A (CAR L)))))) 
         ((EQUAL (CAR L) NIL) 
          (APPEND POS (LIST (EQUAL A NIL))))
         (T POS)))
 (CDR (_SRC A L (LIST NIL))))

现在,我期望从这段代码中得到的输出如下:

  (SRC 'e '(a b e c (e g e) h t e))
> (nil nil t nil (t nil t) nil nil t)

相反,我的代码永远运行,导致堆栈溢出,而且我无法通过调用堆栈或回溯找出任何东西。

【问题讨论】:

    标签: recursion common-lisp


    【解决方案1】:

    由于缺少缩进,代码不可读。

    您的代码不可读,因为您的代码没有缩进。

    (defun SRC (A L) 
    (defun _SRC (A L POS) 
    (COND ((NOT (EQUAL (CAR L) NIL)) (_SRC A (CDR L) (APPEND POS (LIST (EQUAL A (CAR L)))))) 
          ((EQUAL (CAR L) NIL) (APPEND POS (LIST (EQUAL A NIL))))
          (T POS)))
    (CDR (_SRC A L (LIST NIL))))
    

    让我们缩进你的代码。

    (defun SRC (A L) 
      (defun _SRC (A L POS) 
        (COND ((NOT (EQUAL (CAR L) NIL))
               (_SRC A (CDR L) (APPEND POS (LIST (EQUAL A (CAR L)))))) 
              ((EQUAL (CAR L) NIL)
               (APPEND POS (LIST (EQUAL A NIL))))
              (T POS)))
      (CDR (_SRC A L (LIST NIL))))
    

    风格和基本错误

    基本错误或编程风格问题:

    • defun 不应嵌套。 defun 不用于定义本地函数。 defun 只能用于全局函数。将fletlabels 用于本地函数。
    • 使用firstrest 而不是carcdr
    • 使用口语变量
    • 使用小写

    不要从嵌套函数开始

    我会在没有嵌套函数的情况下开始。

    (defun _src (element list pos) 
      (cond ((not (equal (first list) nil))
             (_src a (rest list) (append pos (list (equal element (car list)))))) 
            ((equal (first list) nil)
             (append pos (list (equal element nil))))
            (t pos)))
    
    (defun src (element list)
      (cdr (_src element list (list nil))))
    

    简化递归

    但是你可以使用通常的递归模式大大简化它:

    (defun mark% (element list result) 
      (if (null list)                            
          result                                  ; empty list -> return result
        (mark% element                            ; mark the rest of the list
               (rest list)                        
               (cons (equal element (first list)) ; equal for the first element?
                     result))))
    
    (defun mark (element list)
      "return a list with boolean values if element is found in the list"
      (reverse (mark% element list nil)))         : needs to reverse the result
    

    注意

    一般不要编写这样的递归函数,因为 Lisp 实际上已经提供 MAPMAPCAR - 它们在一个地方提供映射功能,不需要将递归映射烘焙到您自己的每个函数中.

    最好使用更高级别的迭代工具,例如 LOOP:

    CL-USER 13 > (loop for e in '(a b a b)
                       collect (equal 'a e))
    (T NIL T NIL)
    

    嵌套列表

    您可以通过为第一个元素是一个列表添加一个案例测试,然后在这种情况下做一些事情来使上述函数适应嵌套列表...

    (defun mark% (element list result) 
      (cond ((null list)
             result)
            ((consp (first list))
             (mark% element
                    (rest list)                        
                    (cons (mark element (first list))
                          result)))
            (t
             (mark% element
                    (rest list)                        
                    (cons (equal element (first list))
                          result)))))
    

    调试

    使用trace 和/或step 查看您的代码在做什么。

    【讨论】:

    • 虽然这很有价值,但我还需要知道我的代码哪里出错以及为什么它会溢出堆栈..
    • @Subham:我认为您需要先改进您的代码以使其具有可读性。调试不可读和无格式的代码通常是浪费时间。然后我会跟踪这些函数以查看它们在做什么。请参阅宏 CL:TRACE。
    • 那里..我缩进正确,我希望它是正确的。
    • @SubhamBurnwal:最好摆脱嵌套的DEFUNDEFUN 仅用于全局函数。尝试将其用于局部函数是错误的,并且不会产生预期的效果。如果您首先拥有全局函数,那么跟踪它们也更容易 - 尽管有些实现可以跟踪局部函数。
    • 嵌套的 DEFUN 对我来说是愚蠢的。在我所有的 lisp 程序中,我从未嵌套过它。你在这里看到的异常行为是因为我在网上某个地方读到了一个嵌套了 DEFUN 的程序,我想哦,这可能是人们应该做的通常方式,尽管我的教科书没有提到这一点。 我会在问题中更正它,但我希望收到答案后我不会因为编辑而被骂。 :(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-11
    • 1970-01-01
    • 2023-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多