2 Stimmen

Common Lisp: "keine Nicht-White-Space-Zeichen in Zeichenfolge"

Für Project Euler Problem 8, wird mir gesagt, dass ich eine 1000-stellige Zahl durchgehen soll. Das ist eine brute-force-Lisp-Lösung, die im Grunde durch jedes 5-stellige Segment geht und sie von Anfang bis Ende multipliziert und am Ende der Schleife das größte zurückgibt.

Der Code:

(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)))))))

Es kompiliert ohne Warnungen, aber beim Ausführen erhalte ich:

keine Nicht-Whitespace-Zeichen in der Zeichenfolge "73167176531330624919225119674426574742355349194934...".
   [Fehlertyp SB-INT: SIMPLE-PARSE-ERROR]

Ich habe überprüft, ob die lokale Funktion product-of-5n funktioniert, indem ich sie nochmals als globale Funktion geschrieben habe:

(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))))))

Dies kompilierte ohne Warnungen und beim Ausführen scheint es perfekt zu funktionieren. Zum Beispiel,

CL_USER> (product-of-5n 1) => 882

Was korrekt zu sein scheint, da die ersten fünf Ziffern 7, 3, 1, 6 und 7 sind.

Was 1000digits-str betrifft, wurde es einfach mit defvar kompiliert, und mit longlines-show-hard-newlines von Emacs, glaube ich nicht, dass es White-Space-Zeichen in der Zeichenfolge gibt, denn das ist es, worüber SBCL sich beschwert, oder?

3voto

Rainer Joswig Punkte 131198

EVAL ist keine gute Idee.

Deine Schleifen-Obergrenze ist falsch.

Ansonsten habe ich es mit dem Zahlenstring versucht und es funktioniert.

Es ist auch Euler 8, nicht 9.

Dies ist meine Version:

(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)))

3voto

ruakh Punkte 167025

Ich denke nicht, dass es Leerzeichen im String gibt, denn das ist es, worüber sich SBCL beschwert, richtig?

Die Fehlermeldung beschwert sich nicht über die Anwesenheit von Leerzeichen, sondern über das Fehlen von Nicht-Leerzeichen. Aber es ist tatsächlich etwas irreführend: Was die Meldung sagen sollte, ist dass es keine Nicht-Leerzeichen im spezifischen Teilstring gibt, der geparst werden soll. Das liegt daran, dass du am Ende des Strings angekommen bist und somit einen Teilstring der Länge Null geparst hast.

Außerdem ist product-of-5n nicht ganz richtig definiert. Es ist reiner Zufall, dass (product-of-5n 1) das Produkt der ersten fünf Zahlen zurückgibt. Strings sind von 0 an indexiert, also beginnt (product-of-5n 1) mit dem zweiten Zeichen; und die Funktion iteriert von n + 0 bis n + 5, was insgesamt sechs Zeichen sind; also gibt (product-of-5n 1) 3 × 1 × 6 × 7 × 1 × 7 zurück, was zufälligerweise dasselbe ist wie 7 × 3 × 1 × 6 × 7 × 1.

0voto

alexey Punkte 453

Da ich kein Common Lisp kenne, habe ich deinen Code leicht modifiziert, um mit Elisp kompatibel zu sein. Abgesehen von den bereits genannten Fehlern ((product-of-5n 1) sollte 126 zurückgeben), ist mein einziger Kommentar, dass in (pep8) statt -6 die Länge-4 verwendet werden sollte (ansonsten gehen die letzten 2 Zeichen verloren). Tut mir leid, dass ich nicht weiß, wie man deinen Parse-Fehler behebt (ich habe string-to-number verwendet), aber hier ist der Code falls du ihn hilfreich findest:

(defun product-of-5n (n)       ;nimm 5 Zeichen aus einem String "1000-stellige-str", beginnend mit dem n-ten und gib das Produkt davon aus
  (let (ox)                    ;definiere ox als lokale Variable
    (eval                      ;evaluiere
     (append '(*)              ;füge das Multiplikationszeichen zur Liste der 5 Zahlen hinzu (die als nächstes hinzugefügt werden)
         (dotimes (x 5 ox)     ;x geht von 0 bis 4 (n wird später hinzugefügt, um es von n bis n+4 zu machen), das Ergebnis wird in ox gespeichert
           (setq ox (cons      ;erstelle eine Liste von 5 Zahlen und speichere sie in ox 
             (string-to-number 
              (substring 1000-stellige-str (+ x n) (+ (+ x n) 1) ) ;hol das (n+x)-te Zeichen  
              )                ;end konvertiere Zeichen in Zahl
             ox )              ;end cons
             )                 ;end setq
           )                   ;end dotimes, gibt ox außerhalb von do zurück, ox enthält die Liste mit 5 Zahlen
         )                     ;end append
     )                         ;end eval
    )                          ;end let
  )

(defun pep8 () ;gib das größte Produkt aus
  (let ((currentdigit 0) (largestproduct 0))                    ;initialisiere lokale Variablen
    (while  (< currentdigit  (- (length 1000-stellige-str) 4)    ) ;solange currentdigit (cd von jetzt an) kleiner ist als l(str)-4
      ;(print (cons "aktueller Wert von current digit" currentdigit))              ;entkommentiere, um cd auszugeben
      (when (> (product-of-5n currentdigit) largestproduct)     ;wenn das aktuelle Produkt größer ist als das vorherige größte Produkt (lp)
      (setq largestproduct (product-of-5n currentdigit))        ;speichere lp
      (print (cons "nächster guter cd" currentdigit))                ;gebe cd aus
      (print (cons "mit entsprechendem lp" largestproduct))     ;gebe lp aus
      )                                                         ;end wenn
    (setq currentdigit (1+ currentdigit))                       ;erhöhe cd
    )                                                           ;end während
    (print (cons "bisher bestes lp" largestproduct) )               ;gebe bisher bestes lp aus
    )                                                           ;end let
  )

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

was (bei Ausführung auf den ersten 20 Zeichen) zurückgeben würde

"73167176531330624919"
126 

("nächster guter cd" . 0)
("mit entsprechendem lp" . 882)

("nächster guter cd" . 3)
("mit entsprechendem lp" . 1764)

("bisher bestes lp" . 1764)

0voto

Ich habe dieses Problem schon vor einiger Zeit gelöst, und es gibt eine Sache, die in der Beschreibung des Problems fehlt. Sie müssen aufeinanderfolgend als Beginn bei einem beliebigen Offset in einem String lesen, nicht nur die durch 5 teilbaren Offset. Daher wird die Lösung für das Problem eher wie folgt aussehen:

(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)))))

Es ist ein wenig hässlich, aber es veranschaulicht die Idee.

EDIT sorry, ich habe zwei Ihrer Funktionen verwechselt. Daher war der Like falsch.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X