a = (1..1000).lazy.select(&:even?).map{|i| i*2 }.map{|i| i + 1 }.map(&:to_s).map(&:reverse)
There is no benefit from lazy if you do `a.join(",")`, since that iterates over the entire sequence. But if you do `a.take(10)` or `a.detect{|s| s == "14" }`, the chain will only be executed for each item in turn until 10 elements are produced or an element is the string "14", respectively.Ruby's #1 problem, for me at least, is that your small project someday runs into a performance wall. I don't know the latest benchmarks, but last I recall Python was about 8x faster than Ruby when both are being interpreted. Yes, there's JRuby, but that's not something you can drop into a new system and do useful things with immediately (without more setup).
And with Clojure, you get all the elegance and lovely collection manipulation tools you can possibly want, much faster performance, and a huge stable pile of Java libraries (compared to Ruby).
So with Python and Clojure as one's main tools, life is quite nice.
Granted, Python is faster for tasks like those Numpy solves, but in arbitrary execution performance, python is just slower. 8x has NEVER been true. That must have been you doing some really bad stuff in one of them but not both.
For sure, Ruby was slow for what we were doing... processing millions of rows of data was so slow that it caused me to decide to try Go (and the same Go program was hundreds of times faster). But I didn't try Python then.
The lazy version basically turns into
a = ""
(1..1000).each { |i|
next if i.odd?
i *= 2
i += 1
a << i.to_s.reverse + ", " # ya ya, trailing comma
}
Where as the non lazy version turns into: odds = []
(1..1000).each { |i| odds << i if i.even? }
doubled = []
odds.each { |o| doubled << o * 2 }
incremented = []
doubled.each { |d| incremented << d + 1 }
strs = []
incremented.each { |i| i.to_s }
a = ""
strs.each{ |s| a << s.reversed + ", " }
Which means that you have you went from N iterations to 5*N iterations, with 5 intermediate arrays in this case.https://gist.github.com/mboeh/bb480d93c71046e23816f2c24c23e3...
When applied to the same amount of work, lazy iterators consume more memory and take more CPU time than the equivalent non-lazy chained iteration.
There's a place for lazy iterators, but you should pretty much always profile first. If you have performance problems due to a long chain of iterators, you're always going to get better results by merging some of those iterators into a single block than by making the whole chain lazy. The best use case for lazy iterators is if you're trying to avoid having the original collection in memory (if it's being streamed from a file or the like). And at that point, if you're trying to optimize for performance, you should avoid chained iterations, period.
The good news is that in the vast majority of cases this just doesn't matter. Chaining iterators works fine until you start running into performance problems.