Lisp 列出清单

Lisp 列出清单,lisp,common-lisp,Lisp,Common Lisp,我有这张名单上的名字和不同的语言 (setq l '((david spanish german) (amanda italian spanish english) (tom german french))) 我想用一个函数做下一步:对于每种语言,我需要用每种语言传递每个名称 例如,如果我使用列表L调用函数: (lenguages L) 我想展示一下: ( (english (amanda)) (spanish (david amanda)

我有这张名单上的名字和不同的语言

(setq l '((david spanish german)
          (amanda italian spanish english)
          (tom german french)))
我想用一个函数做下一步:对于每种语言,我需要用每种语言传递每个名称

例如,如果我使用列表L调用函数:

(lenguages L)
我想展示一下:

  ( (english (amanda))
    (spanish (david amanda))
    (italian (amanda))
    (german(david tom))
    (french(tom))
  )
我有一个想法如何做到这一点,但它只显示了一个项目

(defun lenguages(names)
   (cond((null names) nil)
    ((list (cadar names) (list (caar names))))))

最后一个函数只显示
(西班牙语(david))
这样基于迭代的任务最适合Common Lisp强大的
循环
宏。您可以在中阅读有关此宏的所有详细信息,但我们只在这里介绍解决此问题所需的部分。让我们从函数定义开始

(defun lenguages (names)
  ...)
在本文中,我们希望遍历提供的列表。我们还想收集一些密钥,因此哈希表将非常有用。哈希表(在许多其他语言中称为映射或dict)以高效的方式将键与值关联起来

(loop with hash = (make-hash-table)
      for entry in names
      for name = (car entry)
      do ...
      finally ...)
循环
宏功能强大,有自己的语言。
with
子句声明一个局部变量,在本例中是一个哈希表。的第一个
定义了一个迭代变量。循环将在
条目
绑定到
名称
的每个条目的情况下运行,并在条目用完时停止。第三行是另一个局部变量,但与
with
不同,
变量的
每次都会反弹,因此在每次迭代时
name
将是
条目的第一个元素。
do
块包含将在每次迭代中执行的任意Lisp代码,
finally
包含将在循环结束时执行的Lisp代码块

do
块中,我们希望将该人员的姓名添加到他们所知道的每种语言的哈希表条目中,因此我们需要另一个
loop
来循环已知语言

(loop for lang in (cdr entry)
      do (push name (gethash lang hash)))
该循环进入外部循环的
do
块内部。对于人员已知语言列表中的每种语言,我们希望在该语言的哈希值前加上该人员的姓名。通常情况下,我们必须考虑哈希密钥不存在的情况,但幸运的是,如果不存在哈希密钥,并且将一个元素添加到nIL/COD> >,创建一个元素列表,这正是我们想要的。 现在,当这个循环完成时,哈希表将包含所有语言和键,以及知道它们是值的人的列表。这是您想要的数据,但不是您想要的格式。事实上,如果我们把它放在
finally
块中

(return hash)
我们会得到一些半有用的结果,告诉我们我们走在正确的轨道上

#S(HASH-TABLE :TEST FASTHASH-EQL ((TOM GERMAN FRENCH) . (TOM TOM))
   ((AMANDA ITALIAN SPANISH ENGLISH) . (AMANDA AMANDA AMANDA))
   ((DAVID SPANISH GERMAN) . (DAVID DAVID)))
相反,让我们再进行一次循环,将此哈希表转换为您想要的列表。下面是我们现在想要的
finally

(return (loop for key being the hash-keys of hash using (hash-value value)
              collect (list key value)))
对于
循环
宏,它使用了相对模糊的
being
语法,允许在哈希表上轻松迭代。您应该这样理解:对于每个键-值对,收集一个包含键和值的列表到一个列表中,然后返回累积列表。这是
循环
宏另一个有趣的特性:它尝试为常见用例提供原语,例如将值累积到列表中。在这种情况下它很方便

这是完整的代码块

(defun lenguages (names)
  (loop with hash = (make-hash-table)
        for entry in names
        for name = (car entry)
        do (loop for lang in (cdr entry)
                 do (push name (gethash lang hash)))
        finally (return (loop for key being the hash-keys of hash using (hash-value value)
                              collect (list key value)))))
我之前提供的链接是关于公共Lisp的GigaMonkeys书籍,它是。我强烈鼓励大家通读它,因为它是所有通用Lisp语言的惊人参考。特别是如果你刚刚开始,那本书真的能为你指明正确的方向



*您的输出格式可能在这方面有所不同。实现选择如何输出结构。

这样一个基于迭代的任务最适合Common Lisp强大的
循环
宏。您可以在中阅读有关此宏的所有详细信息,但我们只在这里介绍解决此问题所需的部分。让我们从函数定义开始

(defun lenguages (names)
  ...)
在本文中,我们希望遍历提供的列表。我们还想收集一些密钥,因此哈希表将非常有用。哈希表(在许多其他语言中称为映射或dict)以高效的方式将键与值关联起来

(loop with hash = (make-hash-table)
      for entry in names
      for name = (car entry)
      do ...
      finally ...)
循环
宏功能强大,有自己的语言。
with
子句声明一个局部变量,在本例中是一个哈希表。
的第一个
定义了一个迭代变量。循环将在
条目
绑定到
名称
的每个条目的情况下运行,并在条目用完时停止。第三行是另一个局部变量,但与
with
不同,
变量的
每次都会反弹,因此在每次迭代时
name
将是
条目的第一个元素。
do
块包含将在每次迭代中执行的任意Lisp代码,
finally
包含将在循环结束时执行的Lisp代码块

do
块中,我们希望将该人员的姓名添加到他们所知道的每种语言的哈希表条目中,因此我们需要另一个
loop
来循环已知语言

(loop for lang in (cdr entry)
      do (push name (gethash lang hash)))
该循环进入外部循环的
do
块内部。对于人员已知语言列表中的每种语言,我们希望在该语言的哈希值前加上该人员的姓名。通常情况下,我们必须考虑哈希密钥不存在的情况,但幸运的是,如果不存在哈希密钥,并且将一个元素添加到nIL/COD> >,创建一个元素列表,这正是我们想要的。 现在,当这个循环完成时,哈希表将包含所有语言和键,以及知道它们是值的人的列表。这是您想要的数据,但不是您想要的格式。事实上,如果我们把它放在我们的
期末考试中