2017-01-18 215 views
0

我想解決一個lisp函數,該函數返回大於列表中第一個數字的NUMBER(count)個數。列表是一個數字的線性列表。LISP FUNCTION - 返回列表中第一個元素大的列表數的個數

(defun foo (lst) 
    (cond ((null lst) 0) 
     (car = k) 
     ((> (car lst) k) 
     (1+ (foo (cdr lst)))) 
    (T (foo (cdr lst))))) 

我的問題是,我不能保留第一個元素,並與其他元素進行比較。

+2

那你試試這麼遠嗎? – coredump

+0

http://clhs.lisp.se/Body/f_countc.htm – coredump

+0

(defun定義FOO(LST) (COND ((空LST)0) (汽車= K) ((>(汽車LST)k)的(1+(foo(cdr lst)))) (T (foo(cdr lst))))) – SomethingGeneral

回答

3

您的正常工作縮進看起來是這樣的:

(defun foo (lst) 
    (cond ((null lst) 0) 
     (car = k)    ; strange cond term   
     ((> (car lst) k)   
     (1+ (foo (cdr lst)))) 
     (T (foo (cdr lst))))) 

我評論過你的COND的第二個任期。這很奇怪。它首先評估變量car(不是函數#'car)。如果car不是nil它首先評估變量=(而不是函數#'=),並且由於它不是cond術語中的最後一個結果表達式,它會將其拋出並返回最後一個爲k

其次,你寫道,你說你使用第一個元素作爲比較,但是你在你的函數中稱它爲k,但它沒有在任何地方定義。在進行遞歸之前,您需要做一些事情,因此您不能讓實際函數執行遞歸,因爲每次都會使用第一個元素。這裏可以使用labels

;; didn't call it foo since it's not very descriptive 
(defun count-larger-than-first (list) 
    (let ((first (car list))) 
    (labels ((helper (list) 
       (cond ((null list) 0) 
        ((> (car list) first) 
         (1+ (helper (cdr list)))) 
        (t (helper (cdr list)))))) 
     (helper (cdr list))))) 

當然。既然你現在必須添加更多的參數的可能性,我會加入累加器:

(defun count-larger-than-first (list) 
    (let ((first (car list))) 
    (labels ((helper (list acc) 
       (cond ((null list) acc) 
        ((> (car list) first) 
         (helper (cdr list) (1+ acc))) 
        (t (helper (cdr list) acc))))) 
     (helper (cdr list) 0)))) 

當然遞歸和可能吹堆棧所以你應該把它寫不Common Lisp中:

(defun count-larger-than-first (list) 
    (let ((first (car list))) 
    (loop :for element :in (cdr list) 
      :counting (> element first)))) 

有跡象表明,算過,這可能是更適合高階函數:

(defun count-larger-than-first (list) 
    (let ((first (car list))) 
    (count-if (lambda (element) (> element first)) 
       (cdr list)))) 
+0

真的非常感謝你的幫助。我測試過它,它的功能非常完美!此外,感謝您在開始時提供的有用建議,我瞭解有關我的錯誤以及使用標籤的所有信息:)! – SomethingGeneral

5

讓我們拆開你的問題:

你有一組數字。真的,你有一個「特殊」的第一個號碼,然後是其他的。具體而言,您可能只需要實數,因爲「小於」在複數(虛數)方面沒有意義。

您可以使用first從列表中獲取第一個數字,爲​​rest獲取其他人員。

其中,您要計算任何不大於第一個的值。

因此,讓我們開始那種僞

(defun count-numbers-greater-than-first (list) 
    ;; split out first and rest 
    ;; call the real count function 
) 

好吧,我們現在知道,我們可以使用firstrest(也,如您使用的,歷史上carcdr),所以:

(defun count-numbers-greater-than-first (list) 
    (count-numbers-greater-than (first list) (rest list)) 

您可能已經知道>用於測試實數是否大於另一個。

就讓我們來看看在CLHS揭示稱爲一個不錯的功能count-if

(defun count-numbers-not-greater-than (reference other-numbers) 
    (count-if ??? other-numbers)) 

???需求是function類型的對象,或函數的名稱。我們需要將reference(第一個數字)「咖喱」到該函數中。這意味着我們要創建一個新函數,該函數僅用於通過count-if的一次運行,該函數已經「關閉」了值reference

如果我們知道number將永遠是說,100,該功能應該是這樣的:

(defun greater-than-100 (number) 
    (> number 100)) 

這個函數然後可以得到在count-if使用:

(defun count-numbers-greater-than (reference other-numbers) 
    (count-if (function greater-than-100) 
       other-numbers)) 

(defun count-numbers-greater-than (reference other-numbers) 
    (count-if #'greater-than-100 other-numbers)) 

但是,並沒有解決將「curried」號碼變成功能的問題。

沒有到達亞歷山大(我會在稍後解釋),您可以使用lambda表單在這裏創建一個新的匿名函數。由於referencecount-numbers-not-greater-than內有效,因此您可以使用該值在lambda之內。讓我們轉換爲100第一:

(defun count-numbers-greater-than (reference other-numbers) 
    (count-if (lambda (number) (> number 100)) 
       other-numbers)) 

現在我們可以使用reference

(defun count-numbers-greater-than (reference other-numbers) 
    (count-if (lambda (number) (> number reference)) 
       other-numbers)) 

而且,事實上,你甚至可以合併這回等功能,如果你想:

(defun count-numbers-greater-than-first (list) 
    (count-if (lambda (number) (> number (first list))) 
       (rest list))) 

那個亞歷山大的東西

但是,亞歷山大呢?亞歷山大是在Quicklisp或其他地方提供的超級實用功能的集合。

(ql:quickload "alexandria") 

(use-package #:alexandria) 

當然,你通常use它在自己的defpackage

(defpackage my-cool-program 
    (:use :common-lisp :alexandria)) 

它提供的東西兩個是curryrcurry功能。事實證明,那裏的lambda函數是一個非常常見的情況。你有一個現有的函數 - 在這裏,> - 你想要一遍又一遍地調用相同的值,還有一些你想要在每次傳遞的未知值。

這些最終找了很多像這樣:

(lambda (x) (foo known x)) 

您可以使用curry寫一樣的東西更簡明:

(curry #'foo known) 

它還與任意數量的參數工作。 RCurry也是如此,但它會將未知值「x」放在左側,而您的已知值放在右側。

(lambda (x) (foo x known)) = (rcurry #'foo known) 

所以另一種方式來寫count-if是:

(defun count-numbers-greater-than-first (list) 
    (count-if (rcurry #'> (first list)) 
       (rest list))) 

* (count-numbers-greater-than-first '(10 9 8 7 11 12)) 

2 
+0

哇,非常感謝你的好解釋,每一個解決方案的作品都很完美,而且完全可以理解! – SomethingGeneral

相關問題