我需要从函数中返回一个序列,一个数字和一个哈希映射(全部包含在向量中),以便打印的返回值如下所示:
[ ([:c :a] [:e :c] [:f :e] [:d :e] [:g :f] [:b :a]) 15
{:g :c, :f :a, :c :e, :d :a, :b :a, :c :a} ]
由于我的输入可能很大,我想从函数中返回延迟序列/对象。 对的序列(我的返回向量中的第一个对象)很容易通过在构建它的conj调用周围包装'lazy-seq'来使其变得懒惰。
哈希映射(我的返回向量中的第三个对象,可能非常大,就像我的序列一样)在与序列相同的循环 - 重复块中构建(使用assoc调用)。哈希映射是我的一些调用者将使用的附加信息,但如果对序列被返回为惰性,那么我想知道是否有意义发回一个潜在的巨大哈希映射与(一个有效的)lazy-seq即使我把它作为一个可选的返回值。散列映射中的条目与惰性序列中的对相关。
所以这是我的noobie问题:在发送一个懒惰的MapEntry序列代替大型HashMap时有什么意义吗?也就是说,假设用户将获取一小部分laEq-Map的MapEntrys,将它们转换为hashmap以进行查找...即可获取下一个块,依此类推。这是一种懒惰地使用关联数据的合理方法吗? 在Clojure中是否有一些惯用的方法来返回/管理大型关联数据? 我很欣赏任何关于我的选择的想法。在此先感谢您的帮助。
答案 0 :(得分:6)
不,给他们一张懒惰的地图是不可能的。一个懒惰的MapEntries序列是可能的,但不是很有用。但是,有许多其他可能有意义的选项是相似的。
你仍然可以返回一个lazy-seq的向量(我不打算让它们成为MapEntries),但是调用者基本上没办法把它当作一个懒惰的地图。要么他们只想查找一组固定的已知密钥(在这种情况下,他们只是懒得过滤条目,从不使它成为地图)或者他们想要任意查找条目,在这种情况下他们会在查找第一个条目后,必须将所有条目保留在内存中,这样它们仍然可以查找第二个条目,因此它们也可以将整个条目转储到完全实现的映射中。
答案 1 :(得分:1)
不,Clojure没有懒人地图。
另外,如果你使用loop / recur构建一个序列,我不相信试图让它变得懒惰可以完成任何事情(除非生成每个元素很慢)。
看看这两个功能:
(defn bad-lazy-range [begin end]
(loop [i (dec end) lst nil]
(if (>= i begin)
(recur (dec i) (lazy-seq (cons i lst)))
lst)))
(defn good-lazy-range [begin end]
(if (>= begin end)
nil
(lazy-seq (cons begin (good-lazy-range (inc begin) end)))))
bad-lazy-range
将重复begin-end
次,每次生成一个thunk(一个懒惰的序列链接),然后返回最外面的thunk。这个thunk需要保持对下一个thunk的引用,这需要引用第三个thunk等。你立即完成所有工作并生成一个伪链接的thunks列表,占用的空间比普通列表要多。< / p>
然而,
good-lazy-range
会立即返回而不会再递增更多 - 递归调用隐藏在thunk中,并且在必要时不会被评估。这也可以防止堆栈溢出异常 - 如果没有lazy-seq
调用,它可能会生成堆栈溢出异常,但在每一步,它都会计算对good-lazy-range
的一次调用并返回。然后调用者可以评估下一个调用,但此时,第一次调用的堆栈帧早已消失。
通常,只有使用lazy-seq
才能将其包含在大量计算中。在第一个函数中,它仅包含在cons
的调用中,无论如何都会快速返回。然而,在第二个函数中,它围绕着对cons
的调用和递归调用,这意味着它会延迟一个有价值的计算量。
如果您的代码正确使用了lazyness并使用了loop / recur,请发布它 - 我很想知道您是如何做到的。
答案 2 :(得分:0)
从你举例说明为什么在所有调用者处返回地图可以使用(进入{} s)从seq构建地图