【问题标题】:In Clojure: Why unable to resolve symbol: hdcit in this context在 Clojure 中:为什么无法解析符号:hdcit 在这种情况下
【发布时间】:2016-01-09 01:11:51
【问题描述】:

我试图解决在nums[i]+nums[j]==target的列表中找到两个数字索引:

(defn two-sum [nums target]
  "Find sum of two numbers equals to target"
  (if (<= 1 (count nums))
    nil)
  (let [hdict (hash-map)]
    (for [i (range 1 (count nums))]
      (if (get hdict (nums i))
        [(get hdict (nums i)) i]        ;return hdict[nums[i]] and i
        (assoc hdcit (- target (nums i)) i)))))

我收到了这个错误:

1. Caused by java.lang.RuntimeException
   Unable to resolve symbol: hdcit in this context

我很困惑:我已经将hdict绑定为hash-map,为什么仍然无法解决?

【问题讨论】:

  • 您在最后一行转换了 ic。不过,还有一些其他问题值得解释

标签: clojure


【解决方案1】:

这个错误是一个简单的错字,但还有其他几点值得考虑:

  • Clojure if 表达式总是返回一个值,如果你没有指定 else 子句(第二个表达式),那么它默认为 nil

所以上面代码中的 if 基本上是这样说的:

 (if contition 
   nil ;; the true case
   nil ;; the false case)

总是返回零。虽然它不是函数中的最后一个表达式,但该值将被忽略,因为:

  • 函数(以及大多数其他表达式)的返回值是表达式中的最后一个值。

您很可能希望将nil 之后的) 移动到函数的末尾。

  • Clojure 数据结构是不可变的,在地图上调用 assoc 会生成一个具有附加值的新地图,同时保持旧地图不变,因为其他人可能正在处理它。

所以最后一行的assoc 永远不会做任何事情。

  • for 不是“for 循环”,而是基于非常强大的表达式“迷你语言”(DSL) 懒惰地产生一系列新值

这意味着它只在读取时产生一个值。所以这个for 循环不会运行,除非有东西打印出这个值。 REPL 将打印此内容并使此功能仅在开发中工作。我称之为“懒虫”。

不可变数据是 Clojure 中的一个核心概念,基本上所有语言的优点,至少部分来自它。


Clojure 的 for 表达式足够强大,可以完全解决这个问题:
user> (let [data [1 2 3 4 5 6 7 42 12]
            target 12]
        (for [x data
              y data
              :when (= (+ x y) target)]
          [x y]))
([5 7] [6 6] [7 5]) 

【讨论】:

  • 非常感谢您的解释。遗憾的是我没有指出数字列表很大——大约 12 500 项;并且需要编号位置/索引,而不是编号本身。这就是我考虑使用hash-map 的原因。 for loop 的时间是 O(n^2),使用 has-map 大约是 O(n)
  • 在这种情况下,您需要重组代码(可能使用递归),以便将 assoc 生成的不可变哈希映射添加到,而不是创建一系列不同且未合并的映射。
  • 值得重申,正如@Arthur Ulfeldt 指出的那样,clojure 中的for 不是循环,它是不可变值的惰性生成器。
猜你喜欢
  • 2016-07-29
  • 1970-01-01
  • 2013-08-15
  • 1970-01-01
  • 2012-04-21
  • 2016-07-17
  • 1970-01-01
相关资源
最近更新 更多