2012-07-18 47 views
2

對於Euler項目Problem 8,我被告知需要解析一個1000位的數字。 這是一個蠻力的Lisp解決方案,它基本上每隔5個連續的數字進行一次,並將它們從開始到結束相乘,並返回循環結尾的最大數字。Common Lisp:「字符串中沒有非空白字符」

代碼:

(defun pep8() 
    (labels ((product-of-5n (n) 
     (eval (append '(*) 
       (loop for x from n to (+ n 5) 
       collect (parse-integer 
       1000digits-str :start x :end (+ x 1))))))) 
    (let ((largestproduct 0)) 
     (do ((currentdigit 0 (1+ currentdigit))) 
      ((> currentdigit (- (length 1000digits-str) 6)) (return largestproduct)) 
     (when (> (product-of-5n currentdigit) largestproduct) 
      (setf largestproduct (product-of-5n currentdigit))))))) 

它編譯沒有任何警告,但在運行它,我得到:

no non-whitespace characters in string "73167176531330624919225119674426574742355349194934...". 
    [Condition of type SB-INT:SIMPLE-PARSE-ERROR] 

我檢查,看看是否本地函數product-of-5n被寫它的工作再作爲全局函數:

(defun product-of-5n (n) 
    (eval (append '(*) 
     (loop for x from n to (+ n 5) 
      collect (parse-integer 
       1000digits-str :start x :end (+ x 1)))))) 

編譯時沒有警告和upo運行它似乎運行得很好。例如,

CL_USER>(產品的-5N 1)=> 882

由於第一5個位數爲7,3,1,6和7

這似乎是正確的

至於1000digits-str,有人簡單地用defvar編譯並與Emacs的longlines-show-hard-newlines,我不認爲在字符串中的任何空白字符,因爲這是SBCL抱怨,對不對?

+0

使用EVAL是不好的。嘗試替換它。 – 2012-07-18 19:17:20

回答

3

我不認爲有字符串中的任何空白字符,因爲這是SBCL抱怨什麼,對吧?

差錯消息不抱怨存在的空白,但關於缺乏非空白。但它實際上有點誤導:消息應該說的是,在特定的子字符串中沒有非空白空間可以被解析。這是因爲你跑掉了字符串的末尾,所以解析了零長度的子字符串。

另外,product-of-5n沒有被定義爲非常正確。只是偶爾(product-of-5n 1)返回前五位的乘積。字符串從0索引,所以(product-of-5n 1)開始於字符;並且函數從 + 0到n + 5迭代,其總共是六個字符;所以(product-of-5n 1)返回3×1×6×7×1×7,這恰好與7×3×1×6×7×1相同。

+0

當我寫下(5n 1的產品)時,我知道有什麼地方是錯誤的......但它確實很晚,我沒有用0來嘗試。謝謝你澄清SBCL真的抱怨! – Soyuz 2012-07-19 00:46:48

4

EVAL不是一個好主意。

您的循環上限是錯誤的。

否則,我試着用數字字符串,它的作品。

這也是歐拉8,不9

這是我的版本:

(defun euler8 (string) 
    (loop for (a b c d e) on (map 'list #'digit-char-p string) 
     while e maximize (* a b c d e))) 
+0

這段代碼讓我很不高興。 您想解釋爲什麼EVAL不是一個好主意嗎? – Soyuz 2012-07-19 00:47:36

+0

沒關係!只是挖了一圈,發現你的答案在這裏: http://stackoverflow.com/questions/2571401/why-exactly-is-eval-evil/2571549#2571549 謝謝! – Soyuz 2012-07-19 01:21:07

0

由於我不知道常見的lisp,我稍作修改你的代碼適合elisp。至於發現錯誤,除了已經說過的((product-of-5n 1)應該返回126),我唯一的評論是在(pep8),長度-4而不是-6(否則你鬆了最後2個字符)。對不起,我不知道如何解決您解析錯誤(我用string-to-number代替),但這裏是在情況下,代碼你覺得它有用:

(defun product-of-5n (n)  ;take 5 characters from a string "1000digits-str" starting with nth one and output their product 
    (let (ox)     ;define ox as a local variable 
    (eval      ;evaluate 
    (append '(*)    ;concatenate the multiplication sign to the list of 5 numbers (that are added next) 
     (dotimes (x 5 ox)  ;x goes from 0 to 4 (n is added later to make it go n to n+4), the output is stored in ox 
      (setq ox (cons  ;create a list of 5 numbers and store it in ox 
      (string-to-number 
       (substring 1000digits-str (+ x n) (+ (+ x n) 1)) ;get the (n+x)th character 
      )    ;end convert char to number 
      ox)    ;end cons 
      )     ;end setq 
      )     ;end dotimes, returns ox outside of do, ox has the list of 5 numbers in it 
     )      ;end append 
    )       ;end eval 
    )       ;end let 
) 

(defun pep8() ;print the highest 
    (let ((currentdigit 0) (largestproduct 0))     ;initialize local variables 
    (while (< currentdigit (- (length 1000digits-str) 4) ) ;while currentdigit (cd from now on) is less than l(str)-4 
     ;(print (cons "current digit" currentdigit))    ;uncomment to print cd 
     (when (> (product-of-5n currentdigit) largestproduct)  ;when current product is greater than previous largestproduct (lp) 
     (setq largestproduct (product-of-5n currentdigit))  ;save lp 
     (print (cons "next good cd" currentdigit))    ;print cd 
     (print (cons "with corresponding lp" largestproduct))  ;print lp 
    )               ;end when 
    (setq currentdigit (1+ currentdigit))      ;increment cd 
    )               ;end while 
    (print (cons "best ever lp" largestproduct))    ;print best ever lp 
    )               ;end let 
) 

(setq 1000digits-str "73167176531330624919") 
(product-of-5n 1) 
(pep9) 

當上了前20個字符跑返回( )

"73167176531330624919" 
126 

("next good cd" . 0) 
("with corresponding lp" . 882) 

("next good cd" . 3) 
("with corresponding lp" . 1764) 

("best ever lp" . 1764) 
+0

原來問題很簡單,我在5n產品中設置的上限是錯誤的,而長度-4不起作用,因爲我正在解析5位數的5位數,所以長度-4意味着我在數字996結束分析,我試圖到達數字1001,但我實際上只有1000。 – Soyuz 2012-07-19 00:55:15

0

我做了這個問題前一段時間, 和有一件事你缺少的問題 的描述。你需要爲開始於任何偏移刺讀取結果,不僅抵消整除5.因此,解決問題的方法會更喜歡以下內容:

(defun pe-8() 
    (do ((input (remove #\Newline 
"73167176531330624919225119674426574742355349194934 
96983520312774506326239578318016984801869478851843 
85861560789112949495459501737958331952853208805511 
12540698747158523863050715693290963295227443043557 
66896648950445244523161731856403098711121722383113 
62229893423380308135336276614282806444486645238749 
30358907296290491560440772390713810515859307960866 
70172427121883998797908792274921901699720888093776 
65727333001053367881220235421809751254540594752243 
52584907711670556013604839586446706324415722155397 
53697817977846174064955149290862569321978468622482 
83972241375657056057490261407972968652414535100474 
82166370484403199890008895243450658541227588666881 
16427171479924442928230863465674813919123162824586 
17866458359124566529476545682848912883142607690042 
24219022671055626321111109370544217506941658960408 
07198403850962455444362981230987879927244284909188 
84580156166097919133875499200524063689912560717606 
05886116467109405077541002256983155200055935729725 
71636269561882670428252483600823257530420752963450")) 
     (tries 0 (1+ tries)) 
     (result 0)) 
     ((= tries 5) result) 
    (setq result 
      (max result 
       (do ((max 0) 
        (i 0 (+ 5 i))) 
        ((= i (length input)) max) 
       (setq max 
         (do ((j i (1+ j)) 
          (current 1) 
          int-char) 
          ((= j (+ 5 i)) (max current max)) 
         (setq int-char (- (char-code (aref input j)) 48)) 
         (case int-char 
          (0 (return max)) 
          (1) 
          (t (setq current (* current int-char)))))))) 
      input (concatenate 'string (subseq input 1) (subseq input 0 1))))) 

這是一點點醜陋,但它說明了這個想法。

編輯對不起,我混淆了你的兩個函數。所以這樣做是不正確的。