# How can I cache param-based Enumerator call results?

**URL:** <https://www.ruby-forum.com/t/how-can-i-cache-param-based-enumerator-call-results/175695>\
**Category:** Ruby\
**Created:** [September 17, 2009, 9:57pm UTC](https://www.ruby-forum.com/t/how-can-i-cache-param-based-enumerator-call-results/175695 "2009-09-17T21:57:13Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Shot\_SPiotr\_S.S](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/e79b87/32.png) [@Shot\_SPiotr\_S.S](https://www.ruby-forum.com/u/Shot_SPiotr_S.S)\
**Post date:** [September 17, 2009, 9:57pm UTC](https://www.ruby-forum.com/t/how-can-i-cache-param-based-enumerator-call-results/175695/1 "2009-09-17T21:57:13Z")

</div>

Iâ€™m trying to cache a lazy-evaluated, param-based Enumerator calls.

Considering the following code:

def arith a, b  
Enumerator.new do |yielder|  
[‘+’, ‘\*’].each do |oper|  
sleep 1 # simulates a param-based, long-running process  
yielder.yield [oper, eval(“#{a} #{oper} #{b}”)]  
end  
end  
end

[[1,2], [3,4], [5,6], [1,2], [3,4], [5,6], [7,8]].each do |a, b|  
arith(a,b).each do |oper, result|  
puts “#{a} #{oper} #{b} = #{result}”  
end  
end

should take about 14 seconds to run, with arith() lazily returning the  
sum and product of its params. Still, if you look closely, arith(1,2),  
arith(3,4) and arith(5,6) are called twice; if there was caching of  
the yielded values there would be no need to recompute these sums  
and products (and the whole process would take around eight seconds  
instead).

Iâ€™m still rather new to Enumerators, but in my project their lazy  
evaluation is an amazing benefit. Whatâ€™s the best/simplest way to  
introduce caching in the above scenario?

(Ideally, Iâ€™d love to have the caching done outside the Enumerator,  
as in my projectâ€™s case the arith() method is provided by various  
interchangeable modulesÂ¹, but if itâ€™s only â€“ or much easier â€“ doable  
from inside the Enumerator then so be it, Iâ€™ll add it in every  
implementationâ€¦)

Â¹

> <https://github.com/Chastell/art-decomp/blob/master/lib/art-decomp/decomposer.rb>

â€“ ignoring that #decompositions is itself an Enumerator, what I want is  
for qv\_gen to not recompute blankets if qv\_gen.blankets(fsm, u, v, qu)  
was already called previously with the same params

Thanks in advance for any insight in how to solve this problem!

â€” Shot

---

<div class="post-metadata">

**Author:** ![Shot\_SPiotr\_S.S](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/e79b87/32.png) [@Shot\_SPiotr\_S.S](https://www.ruby-forum.com/u/Shot_SPiotr_S.S)\
**Post date:** [September 19, 2009, 12:05pm UTC](https://www.ruby-forum.com/t/how-can-i-cache-param-based-enumerator-call-results/175695/2 "2009-09-19T12:05:24Z")

</div>

Shot (Piotr S.):

> Iâ€™m trying to cache a lazy-evaluated, param-based Enumerator calls.

> Considering the following code:

> def arith a, b  
> Enumerator.new do |yielder|  
> [’+’, ‘\*’].each do |oper|  
> sleep 1 # simulates a param-based, long-running process  
> yielder.yield [oper, eval("#{a} #{oper} #{b}")]  
> end  
> end  
> end

> [[1,2], [3,4], [5,6], [1,2], [3,4], [5,6], [7,8]].each do |a, b|  
> arith(a,b).each do |oper, result|  
> puts “#{a} #{oper} #{b} = #{result}”  
> end  
> end

> should take about 14 seconds to run, with arith() lazily returning the  
> sum and product of its params. Still, if you look closely, arith(1,2),  
> arith(3,4) and arith(5,6) are called twice; if there was caching of  
> the yielded values there would be no need to recompute these sums  
> and products (and the whole process would take around eight seconds  
> instead).

I ended up doing the below, which nicely caches the stuff outside the  
Enumerator. Any improvements (I have a feeling that the eachâ€¦putsâ€¦end  
blocks can be DRY-ed up by factoring them out) most welcome, of course!

def arith a, b  
Enumerator.new do |yielder|  
[’+’, ‘\*’].each do |oper|  
sleep 1 # simulates a param-based, long-running process  
yielder.yield [oper, eval("#{a} #{oper} #{b}")]  
end  
end  
end

cache = {}  
[[1,2], [3,4], [5,6], [1,2], [3,4], [5,6], [7,8]].each do |a, b|  
if cache[[a,b]]  
cache[[a,b]].each do |oper, result|  
puts “#{a} #{oper} #{b} = #{result}”  
end  
else  
cache[[a,b]] = []  
arith(a,b).each do |oper, result|  
puts “#{a} #{oper} #{b} = #{result}”  
cache[[a,b]] \<\< [oper, result]  
end  
end  
end

â€” Shot
