Clojure中的功能查询

时间:2019-01-19 19:59:14

标签: clojure

帮我,我需要编写查找函数,该函数在列表中查找值,因为每个元素都是按顺序排列的(键值)。 例如

((key1 value1) (key2 value2) ....)

此功能必须为

(look-up key list-of-lists)

并返回具有键的列表的值。 例如:

(look-up b '(((a b) 1) (c 2) (b 3)))3
(look-up (a b) '(((a b) 1) (c 2) (b 3)))1
(look-up d '(((a b) 1) (c 2) (b 3)))nil

我有此代码:

(defn look-up [key list-of-lists]
  (if (= key (first(first list-of-lists))) (second(first list-of-lists)))
  (:else (look-up (rest list-of-lists key))))

5 个答案:

答案 0 :(得分:3)

(defn lookup [x xs]
  (first (for [[k v] xs :when (= k x)]
           v)))

答案 1 :(得分:2)

这是一个可以使用的简单版本:

(defn lookup
  [k lol]
  (let [the-map (into {}
                  (for [lst lol]
                    {(first lst) (second lst) } ))
        result (get the-map k)]
    result ) )

(lookup (quote b)      (quote (((a b) 1) (c 2) (b 3)))) => 3
(lookup (quote [a b])  (quote (((a b) 1) (c 2) (b 3)))) => 1
(lookup (quote d)      (quote (((a b) 1) (c 2) (b 3)))) => nil

但是,如果您将所有'(1 2 3)等带引号的列表替换为[1 2 3]这样的向量(那么就不需要前导引号),并替换所有引号,例如{ {1}}带有诸如'a之类的关键字(也不需要引用符号。

进行这些更改并添加单元测试如下所示:

:a

P.S。请see Brave Clojure了解更多详情。


更新

您不能使用具有以下语法的常规函数​​:

(ns tst.demo.core
  (:use tupelo.core demo.core tupelo.test) )

(defn lookup
  [k lol]
  (get (into {} lol) k))

(dotest
  (is= 3    (lookup :b      [[[:a :b] 1] [:c 2] [:b 3]]))
  (is= 1    (lookup [:a :b] [[[:a :b] 1] [:c 2] [:b 3]]))
  (is= nil  (lookup :d      [[[:a :b] 1] [:c 2] [:b 3]])))

由于(look-up b '(((a b) 1) (c 2) (b 3))) 是一个符号,因此是变量,而不是数据。您的选择:

  1. 按照我的建议将符号b转换为关键字b
  2. 总是引用:b之类的符号(痛苦且容易出错)
  3. 编写一个宏(该宏会自动“引用”其所有参数),并让该宏调用'b函数的第一个版本(为获取小利益而进行的大量工作)。

这就是我建议将项目(1)作为首选解决方案的方式。

答案 2 :(得分:1)

您的代码几乎正确。我修复的两件事是:

  • “ if”的语法带有3个参数:一个测试和两个值(对于该测试的每个布尔结果)。不需要:else(通常在使用cond时用于突出显示默认分支。

  • 继续查看其余列表列表的递归调用的参数顺序错误。

更正后的函数如下:

(defn look-up [key list-of-lists]                                                                                                                                                    
  (if (= key (first (first list-of-lists)))                                                                                                                                          
    (second (first list-of-lists))                                                                                                                                                   
    (look-up key (rest list-of-lists))))                                                                                                                                             

;; (look-up 'b '(((a b) 1) (c 2) (b 3))) ;; => returns 3                                                                                                                             

注意:

  • 您可以使用其他功能(例如ffirst简化此代码,请参见https://clojuredocs.org/clojure.core/ffirst
  • 您仍然需要改进它以解决以下情况:1.- empty list和2.-寻找不存在的密钥。如果您致电(look-up 'x '(((a b) 1) (c 2) (b 3)))会发生什么?

答案 3 :(得分:1)

只需一点模式匹配...

(require '[meander.match.alpha :as pm])
(letfn [(lookup [KEY LIST]
            (pm/find LIST
                     (_ ... (~KEY ?v) . _ ...) ?v))]
    (let [LIST '(((a b) 1) (c 2) (b 3))]
        [(lookup 'b LIST)
         (lookup '(a b) LIST)
         (lookup 'd LIST)]))
=> [3 1 nil]

对于这样一个简单的案例,这是一个过大的杀伤力,但是这里提供了一些更高级的使用案例的线索。

答案 4 :(得分:0)

您要在列表中找到符合某些条件的第一项(请检查该项的第一个元素),然后对该项做些事情(获取其第二个元素)。

Clojure cheatsheet建议使用somefilter搜索序列。

  • 一些
(defn lookup
  [x col]
  (some (fn [[k v]]
          (when (= x k) v))
        col))
  • 过滤器
(defn lookup
  [x col]
  (->> col
       (filter (fn [[k v]]
                 (when (= x k) v)))
       first))

  • 列表理解

也是一个不错的选择。参见amalloy's answer

  • 通用解决方案,如果您想发疯

您可以使用上述任何一种方法来完成此操作。

(defn lookup
  [pred f col]
  (some (fn [x]
          (when (pred x)
            (f x)))
       col))

(defn lookup
  [pred f col]
  (first (for [x col :when (pred x)]
           (f x))))

;; usage: (lookup (comp '#{b} first) second data)