我有一个无限的列表:
((1 1)(3 9)(5 17)......)
我想用它制作哈希图:
{:1 1:3 9:5 17 ...)
基本上,“内部”列表的第一个元素是关键字,第二个元素是值。我不确定在创建时创建我使用的列表是否更容易:
(iterate(fn [[a b]] [(a的计算)(b的计算)])[1 1])
(b)的计算需要(a)所以我相信在这一点上(a)不能成为一个关键词......这一点的全部意义在于,人们可以轻易地获得给定(a)的值(b)。
非常感谢任何想法...
- EDIT--
好的,我明白了:
(def my-map(into {}(map#(hash-map(keyword(str(first%)))(first(rest%)))my-list)))
问题是:它似乎并不是懒惰的......即使我没有消耗它,它也会永远存在。有没有办法强迫它变懒?
答案 0 :(得分:3)
问题是哈希映射既不是无限的也不是懒惰的。它们专为快速键值访问而设计。因此,如果您有哈希映射,您将能够执行快速键查找。键值访问是哈希映射的核心思想,但它使得创建惰性无限哈希映射变得不可能。
假设我们有一个无限的2d列表,那么你可以使用into
创建哈希映射:
(into {} (vec (map vec my-list)))
但无法使这个哈希图无限。因此,唯一的解决方案是创建自己的哈希映射,如Chouser suggested。在这种情况下,你将拥有一个无限的2d序列和一个在其中执行惰性密钥查找的函数。
实际上,他的解决方案可以略微改进:
(def my-map (atom {}))
(def my-seq (atom (partition 2 (range))))
(defn build-map [stop]
(when-let [[k v] (first @my-seq)]
(swap! my-seq rest)
(swap! my-map #(assoc % k v))
(if (= k stop)
v
(recur stop))))
(defn get-val [k]
(if-let [v (@my-map k)]
v
(build-map k)))
我的示例中的 my-map
存储当前的哈希映射,my-seq
存储尚未处理的元素的序列。 get-val
函数使用my-map
中已处理的元素执行惰性查找,以提高其性能:
(get-val 4)
=> 5
@my-map
=> {4 5, 2 3, 0 1}
加速:
(time (get-val 1000))
=> Elapsed time: 7.592444 msecs
(time (get-val 1000))
=> Elapsed time: 0.048192 msecs
答案 1 :(得分:1)
如果你将它压平到一个(k v k v k v k v)列表并使其变平,那么你可以使用apply来调用该列表的hash-map作为它的参数,它将引导你寻找的列表。
user> (apply hash-map (flatten '((1 1)(3 9)(5 17))))
{1 1, 3 9, 5 17}
虽然没有关键字化第一个参数。
至少在clojure 中,与键关联的最后一个值被称为该键的值。如果不是这种情况,则无法为映射中已存在的键生成具有不同值的新映射,因为查找函数将返回第一个(现在为阴影的键)。如果查找函数搜索到结尾,那么它不是懒惰的。您可以通过编写自己的使用关联列表的地图实现来解决这个问题,尽管它缺乏Clojure基于trei的地图的性能保证,因为它会在最坏的情况下转换为线性时间。
我不确定保持输入序列是否具有所需的结果。
答案 2 :(得分:1)
为了保持懒惰,计算机必须在每次请求密钥时对输入序列进行线性扫描,至少如果密钥超出了目前已扫描的密钥。一个天真的解决方案就是每次扫描序列,如下所示:
(defn get-val [coll k] (some (fn [[a b]] (when (= k a) b)) coll)) (get-val '((1 1)(3 9)(5 17)) 3) ;=> 9
稍微不那么天真的解决方案是使用memoize
来缓存get-val
的结果,尽管这仍然会扫描输入序列而不是严格必要的。一个更积极的缓存解决方案是使用一个原子(如内部memoize
所做的那样)来缓存看到的每一对,从而在查找需要尚未看到的东西时只消耗更多的输入序列。
无论如何,我不建议将其包装在哈希映射API中,因为这意味着有效的不可变“更新”可能不需要而且很难实现。我通常也不建议将密钥用于关键字。
答案 3 :(得分:0)
要从序列中创建一个hashmap,您可以尝试:
(defn to-map [s] (zipmap (map (comp keyword str first) s) (map second s)))
=> (to-map '((1 1)(3 9)(5 17)))
=> {:5 17, :3 9, :1 1}
答案 4 :(得分:0)
您可以稍后将该结构转换为哈希图
(def it #(iterate (fn [[a b]] [(+ a 1) (+ b 1)]) [1 1]))
(apply hash-map (apply concat (take 3 (it))))
=> {1 1, 2 2, 3 3}