将带有列表的多行文本文件转换为 Common Lisp 中的哈希表
Convert multi-line text file with lists to hashtable in Common Lisp
假设我有一个格式如下的文本文件:
(:question
(hello
how
are
you))
(:answer
(i
am
fine
thanks))
我希望阅读然后将其转换为哈希表,其中第一个单词(以 : 开头)是键,然后内部列表是给定键的值。我怎样才能做到这一点?我已经尝试了几种方法来解决这个问题,但我找不到读取文件然后将其转换为哈希表的好方法。
我设法使用以下代码解决了问题:
(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))
既然您发布了 ,可能值得比较如何更简单地完成它。 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))))
假设我有一个格式如下的文本文件:
(:question
(hello
how
are
you))
(:answer
(i
am
fine
thanks))
我希望阅读然后将其转换为哈希表,其中第一个单词(以 : 开头)是键,然后内部列表是给定键的值。我怎样才能做到这一点?我已经尝试了几种方法来解决这个问题,但我找不到读取文件然后将其转换为哈希表的好方法。
我设法使用以下代码解决了问题:
(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))
既然您发布了
(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))))