【问题标题】:Convert multi-line text file with lists to hashtable in Common Lisp在 Common Lisp 中将带有列表的多行文本文件转换为哈希表
【发布时间】:2015-10-06 09:17:33
【问题描述】:

假设我有一个格式如下的文本文件:

(:question
 (hello
  how
  are
  you))

(:answer
 (i
  am
  fine
  thanks))

我希望读取然后转换成一个哈希表,其中第一个单词(以 : 开头)是键,然后内部列表是给定键的值。我怎样才能做到这一点?我尝试了几种方法来解决这个问题,但我找不到读取文件然后将其转换为哈希表的好方法。

【问题讨论】:

  • 如果您尝试了多种方法,请公开您更有信心的方法,作为先前努力的证明和起点。
  • 如果你直接使用 plist 而不是几乎一个会更容易。那么你可以使用#'read#'alexandria:plist-hash-table

标签: list file-io common-lisp hashtable


【解决方案1】:

由于您发布了an attempt,可能值得比较一下如何更简单地完成它。 loop 宏支持许多不同的子句,其中一些在这里非常方便。如果我知道我可以从流中读取表单(键值)的值,直到没有更多值为止(在这种情况下,直到读取 nil 或遇到流的结尾),我会做这样的事情:

(defun read-hashtable (&optional (stream *standard-input*))
  (loop
     with table = (make-hash-table)         ; the hash table
     with sentinel = (cons 1 1)             ; unique value for EOF
     for x = (read stream nil sentinel nil) ; read value, sentinel if EOF
     until (eq sentinel x)                  ; until EOF, indicated by sentinel
     do (setf (gethash (first x) table) (second x)) ; set a value in the table
     finally (return table)))                       ; finally return the table

那么你可以这样使用它:

(with-open-file (in ".../input.txt")
  (read-hashtable in))
;=> #<HASH-TABLE :TEST EQL :COUNT 2 {10056B2C43}>

如果您不喜欢 loop,也可以使用 do 轻松做到这一点:

(defun read-hashtable (&optional (stream *standard-input*))
  (do* ((sentinel (cons 1 1))
        (table (make-hash-table))
        (x (read stream nil sentinel nil) (read stream nil sentinel nil)))
       ((eq x sentinel) table)
    (setf (gethash (first x) table) (second x))))

【讨论】:

    【解决方案2】:

    我设法使用以下代码解决了这个问题:

    (defun symbols-to-lowercase-strings (sym-list)
      (let ((newlist (list '())))
        (loop for symbol in sym-list
           do (progn
            (setf symbol (string symbol))
            (setf symbol (string-downcase symbol))
            (push symbol newlist)))
        (subseq newlist 0 (- (length newlist) 1))))
    
    (defun read-file (filename)
      (let ((classes (make-hash-table :test #'equal))
        (class-lists NIL))
        (with-open-file (stream filename :direction :input)
          (loop
         for line = (read stream nil)
         while line
         collect line
         do (push (cons (car line) (cdr line)) class-lists))
          (loop for line in class-lists
         do (setf (gethash (car line) classes) (list (symbols-to-lowercase-strings (car (cdr line))) '(0)))))
        classes))
    

    【讨论】:

      猜你喜欢
      • 2012-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-31
      相关资源
      最近更新 更多