2016-07-10 3 views
2

Also ich versuche, ein 2D-Array von Standard-Eingabe in eine Datenstruktur in Common Lisp (SBCL) zu analysieren. Ich erwarte, dass der Eingang der Form seinParse ein 2D-Array von Eingabe in Common Lisp

1 2 3 
4 5 6 
7 8 9 

wenn es 3 Zeilen.

Bisher habe ich diese bekommen:

(defun read-2d-array (rows &rest args) 
    (values (read-from-string 
      (concatenate 'string "#2A(" 
          (dotimes (i rows) 
          (concatenate 'string "(" 
             (apply #'read-line args) 
             ")")) 
          ")")))) 

Das Problem dabei ist, dass, während die äußere verketten zu funktionieren scheint, Ich habe Schwierigkeiten beim Versuch, über die Schleifendurchläufe verketten und die Form erhalten:

#2A((1 2 3)(4 5 6)(7 8 9)) 

Jede Hilfe wird geschätzt. Vielen Dank!

Antwort

1

diese Verkettungs ist Alles nicht der beste Ansatz.

Common Lisp kann mit Strings lesen und drucken. drucken

nur in einen String Ausgabestrom, erstellt von WITH-OUTPUT-TO-STRING:

(defun convert-text-to-array-string (stream) 
    (with-output-to-string (out-stream) 
    (write-string "#2A(" out-stream) 
    (loop for line = (read-line stream nil nil) 
      while line 
      do 
      (write-string "(" out-stream) 
      (write-string line out-stream) 
      (write-string ")" out-stream)) 
    (write-string ")" out-stream))) 

Wenn aus WITH-OUTPUT-TO-STRING zurückzugeben, gibt die Form der Zeichenfolge von dem Ausgang zu dem Strom getan führt.

0

Ihr dotimes Formular gibt nil zurück.

Sie müssen die Linien verketten Sie lesen:

(defun read-2d-array (rows &rest args) 
    (values (read-from-string 
      (concatenate 'string "#2A(" 
         (apply #'concatenate 'string 
           (loop :repeat rows 
           :collect (apply #'read-line args))) 
         ")")))) 
2

Es wäre besser, die invidual Zahlen mit PARSE-INTEGER zu analysieren und sie in ein Array setzen Sie sich, anstatt einen String zu machen und eine wörtliche Array Auslesen davon.

(defun read-2d-array (rows &rest args) 
    ;; I'm assuming that the array is a square matrix. Otherwise you'd 
    ;; need the number of columns too. 
    (let ((arr (make-array (list rows rows) 
         :element-type 'integer 
         :initial-element 0))) 
    (dotimes (i rows) 
     (let ((line (apply #'read-line args)) 
      (start 0)) 
     (dotimes (j rows) 
      (multiple-value-bind (number end) 
       (parse-integer line :start start 
            :junk-allowed t) 
      (setf start end 
        (aref arr i j) number))))) 
    arr)) 

(with-input-from-string (str "1 2 3 
4 50 6 
7 8 9") 
    (read-2d-array 3 str)) 
;=> #2A((1 2 3) (4 50 6) (7 8 9)) 

bearbeiten

nur um sicher zu sein, hier ist eine Version, die in der ersten Zeile der Eingabe, indem Sie die Anzahl der Spalten herausfindet.

(defun read-2d-array (rows &rest args) 
    (let* ((first-line (apply #'read-line args)) 
     (cols (1+ (count #\space first-line))) 
     (arr (make-array (list rows cols) 
          :element-type 'integer 
          :initial-element 0))) 
    (loop for i below rows 
      for line = first-line then (apply #'read-line args) 
      for start = 0 
      do (dotimes (j cols) 
       (multiple-value-bind (number end) 
        (parse-integer line :start start 
             :junk-allowed t) 
       (setf start end 
         (aref arr i j) number)))) 
    arr)) 

oder CL-PPCRE mit ganzen Zahlen aus der Leitung zu extrahieren:

(defun read-2d-array (rows &rest args) 
    (labels ((numbers (string) 
      (mapcar #'parse-integer 
        (cl-ppcre:all-matches-as-strings "\\d+" string)))) 
    (let* ((first-line (numbers (apply #'read-line args))) 
      (cols (length first-line)) 
      (arr (make-array (list rows cols) 
          :element-type 'integer 
          :initial-element 0))) 
     (loop for i below rows 
      for line = first-line then (numbers (apply #'read-line args)) 
      do (dotimes (j cols) 
       (setf (aref arr i j) (pop line)))) 
     arr))) 
+0

Ich glaube nicht, dass die Frage die Anzahl der Zeilen und Spalten im Voraus zu wissen ist? – BRFennPocock

+0

@BRPocock Die Funktion in der Frage hat "rows" als Argument. Da die Beispieleingabe ein Quadrat war, dachte ich, es wäre sicher anzunehmen, dass die Zahlenspalten dasselbe wären (oder zumindest bekannt wären). – jkiiski

+0

Nur raten, dass das OP nach etwas wie einem generischen "CSV" -Leser suchen könnte, aber definitiv nicht in Frage gestellt – BRFennPocock