How Do Enumerators Work in Ruby 1.9.1

How do Enumerators work in Ruby 1.9.1?

Here's a plain ruby enumerator that uses Fibers and should pretty much behave like the original:

class MyEnumerator
include Enumerable

def initialize(obj, iterator_method)
@f = Fiber.new do
obj.send(iterator_method) do |*args|
Fiber.yield(*args)
end
raise StopIteration
end
end

def next
@f.resume
end

def each
loop do
yield self.next
end
rescue StopIteration
self
end
end

And in case anyone is feeling uneasy about using exceptions for control flow: The real Enumerator raises StopIteration at the end, too, so I just emulated the original behaviour.

Usage:

>> enum = MyEnumerator.new([1,2,3,4], :each_with_index)
=> #<MyEnumerator:0x9d184f0 @f=#<Fiber:0x9d184dc>
>> enum.next
=> [1, 0]
>> enum.next
=> [2, 1]
>> enum.to_a
=> [[3, 2], [4, 3]]

Equivalent of Ruby Enumerable.collect that returns an Enumerable?

Ruby 2.0 introduced Enumerable#lazy which allows one to chain map, select, etc..., and only generate the final results at the end with to_a, first, etc... You can use it in any Ruby version with require 'backports/2.0.0/enumerable/lazy'.

require 'backports/2.0.0/enumerable/lazy'
names = (1..Float::INFINITY).lazy.map{|i| "hacker_" + String(i) }
names.first # => 'hacker_1'

Otherwise, you can use Enumerator.new { with_a_block }. It's new in Ruby 1.9, so require 'backports/1.9.1/enumerator/new' if you need it in Ruby 1.8.x.

As per your example, the following will not create an intermediate array and will only construct the needed strings:

require 'backports/1.9.1/enumerator/new'

def find_me_an_awesome_username
awesome_names = Enumerator.new do |y|
(1..1000000).each {|i| y.yield "hacker_" + String(i) }
end
awesome_names.find {|n| not stackoverflow.userexists(n) }
end

You can even replace the 100000 by 1.0/0 (i.e. Infinity), if you want.

To answer your comment, if you are always mapping your values one to one, you could have something like:

module Enumerable
def lazy_each
Enumerator.new do |yielder|
each do |value|
yielder.yield(yield value)
end
end
end
end

awesome_names = (1..100000).lazy_each{|i| "hacker_#{i}"}

Why Ruby's array of 1000 hashes' key and value pairs are always in a particular order?

The layout of the hash is deterministic. So for a particular version of ruby, if you always add/remove the keys of a hash in the same order, the layout of the hash will be the same. This means iterating over the hashes in your array will have the keys all in the same order.

Segmentation fault' when executing Enumerator#next in rails console

I don't see an issue for this reported against Ubuntu, but I do see one for OS X Lion. You might consider figuring out where exactly to report the issue against 1.9.2 and try to see if anyone in the community there can give you more guidance on how to get a bug report (a) verified as an actual bug and not caused by something else, and (b) where and how to file the bug if it does get verified.

I don't believe you're supposed to create issues directly in the backport page, but at least for reference here are the list of issues on the 1.9.2 backport list.

  • https://bugs.ruby-lang.org/projects/ruby-192/issues?set_filter=1

Ruby 1.9.1 standard library documentation online anywhere?

Try this:

http://yardoc.org/docs/ruby-stdlib

and this:

http://yardoc.org/docs/ruby-core

Iterate over an infinite sequence in Ruby

In Ruby >= 1.9, you can create an Enumerator object that yields whatever sequence you like. Here's one that yields an infinite sequence of integers:

#!/usr/bin/ruby1.9

sequence = Enumerator.new do |yielder|
number = 0
loop do
number += 1
yielder.yield number
end
end

5.times do
puts sequence.next
end

# => 1
# => 2
# => 3
# => 4
# => 5

Or:

sequence.each do |i|
puts i
break if i >= 5
end

Or:

sequence.take(5).each { |i| puts i }

Programming Ruby 1.9 (aka "The Pickaxe Book"), 3rd. ed., p. 83, has an example of an Enumerator for triangular numbers. It should be easy to modify the Enumerator above to generate triangular numbers. I'd do it here, but that would reproduce the example verbatim, probably more than "fair use" allows.



Related Topics



Leave a reply



Submit