从Common Lisp中的输入解析2D数组

时间:2016-07-10 02:57:47

标签: multidimensional-array common-lisp

所以我试图将标准输入的2D数组解析为Common Lisp(SBCL)中的数据结构。 我希望输入的格式为

1 2 3
4 5 6
7 8 9

如果它有3行。

到目前为止,我已经得到了这个:

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

这个问题是,虽然外部连接似乎有效,但我在尝试连接循环迭代并获取表单时遇到了麻烦:

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

任何帮助将不胜感激。谢谢!

3 个答案:

答案 0 :(得分:2)

最好用PARSE-INTEGER解析不变数字并将它们自己放入数组中,而不是制作一个字符串并从中读取一个文字数组。

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

修改

为了安全起见,这是一个通过查看第一行输入来计算列数的版本。

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

或者使用CL-PPCRE从行中提取整数:

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

答案 1 :(得分:1)

所有这些连接并不是最好的方法。

Common Lisp可以使用字符串进行读取和打印。

只需打印到由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)))

WITH-OUTPUT-TO-STRING返回时,表单返回完成输出到输出结果的字符串。

答案 2 :(得分:0)

您的dotimes表单会返回nil

您需要连接您阅读的行:

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