检索嵌套的assoc列表中的值的最佳方法?


11

假设我有一个这样的assoc列表:

(setq x '((foo . ((bar . "llama")
                  (baz . "monkey")))))

我想要的价值bar。我可以做这个:

(assoc-default 'bar (assoc-default 'foo x))

但是我真正想要的是可以接受多个键的东西,例如

(assoc-multi-key 'foo 'bar x)

这样的东西是否存在,也许在某个地方的包装中?我敢肯定我会写的,但是我觉得我的Google-fu只是失败了,我找不到它。


FWIW,我在此页面上没有看到任何嵌套的列表。我只看到普通的,没有嵌套的清单。目前尚不清楚您要寻找的行为。您没有说出的行为assoc-multi-key。大概它寻找与它的前两个参数都匹配的东西,但是实际上,根据您的说法,这就是所有可能的假设。而且它显然不能接受两个以上的键,因为alist参数(大概是x)是最后一个,而不是第一个-这表明它通常不太有用。尝试实际指定您要查找的内容。
Drew

我还在setq示例中发现表单的原始格式令人困惑,因此我对其进行了编辑,以对assoc-list使用通用的点符号。
辣椒粉

喔好吧。因此,名单确实有两个层次。问题仍然不清楚- assoc-multi-key仍未确定。
提请2014年

1
Drew:的assoc-multi-key重点是在assoc列表中查找第一个键。这应该解析为一个新的assoc列表,我们在其中查找下一个键。依此类推。基本上是从嵌套的assoc列表中挖掘值的捷径。
abingham

2
@Malabarba也许您也可以提及let-alist?例如(let-alist '((foo . ((bar . "llama") (baz . "monkey")))) .foo.bar)将返回"llama"。我想您let-alist是在提出问题后写的,但这是问题的精神,非常值得一提的IMO!
YoungFrog 2015年

Answers:


15

这是一个选项,它以通用的方式采用您所要求的确切语法,并且很容易理解。唯一的区别是,该ALIST参数需要排在第一位(如果这对您很重要,则可以将其调整为排在最后)。

(defun assoc-recursive (alist &rest keys)
  "Recursively find KEYs in ALIST."
  (while keys
    (setq alist (cdr (assoc (pop keys) alist))))
  alist)

然后可以使用以下命令调用它:

(assoc-recursive x 'foo 'bar)

2
这差不多是我煮过的。令我感到有些惊讶的是,这不是诸如dash之类的某些已建立库的一部分。在处理例如json数据时,似乎一直都在出现。
abingham

2

这是一个更通用的解决方案:

(defun assoc-multi-key (path nested-alist)
   "Find element in nested alist by path."
   (if (equal nested-alist nil)
       (error "cannot lookup in empty list"))
   (let ((key (car path))
         (remainder (cdr path)))
     (if (equal remainder nil)
         (assoc key nested-alist)
       (assoc-multi-key remainder (assoc key nested-alist)))))

它可以采用键的任何“路径”。这将返回(bar . "llama")

(assoc-multi-key '(foo bar)
    '((foo (bar . "llama") (baz . "monkey"))))

而这将返回(baz . "monkey")

(assoc-multi-key '(foo bar baz)
    '((foo (bar (bozo . "llama") (baz . "monkey")))))

3
得到了我的第一个downvote这个答案。有人愿意告诉我为什么吗?
rekado 2014年

1
由于您的代码有效(+1),因此我不同意这种观点。我的猜测是,@ Malabarba的答案显然比提供的其他答案更笼统/更优雅,因此其他答案之所以被否决,并不是因为它们不起作用,而是因为它们不是最佳答案。(话虽这么说,我更喜欢“赞成最好”,而不是“赞成最好,而其他则不赞成”。)

1
这两个问题都被否决了,因为这里有一个人不太了解否决的工作方式(并选择不理会界面的请求发表评论)。不幸的是,我们所有人能做的最好的就是投票。
马拉巴巴2014年

0

这是一个与嵌套在另一个列表中的列表一起使用的简单函数:

(defun assoc2 (outer inner alist)
  "`assoc', but for an assoc list inside an assoc list."
  (assoc inner (assoc outer alist)))

(setq alist2 '((puppies (tail . "waggly") (ears . "floppy"))
               (kitties (paws . "fuzzy")  (coat . "sleek"))))

(assoc2 'kitties 'coat alist2)       ;; => (coat . "sleek")
(cdr (assoc2 'kitties 'coat alist2)) ;; => "sleek"

3
请人们在您投反对票时发表评论。
马拉巴巴

1
反对的人:我没有被冒犯,但是很好奇为什么。@Malabara:现在有关于“ downvote + comment”规范的元线程; 我会对你的想法感到好奇。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.