How to write a generator in Ruby? [duplicate] - ruby

This question already has answers here:
Are there something like Python generators in Ruby?
(5 answers)
Closed 6 years ago.
In Python, we can write something like this to generate all positive integers:
def integer():
count = 0
while True:
count += 1
yield count
Is there a way to write a similar generator in Ruby?

It's very similar:
def integer
Enumerator.new do |y|
n = 0
loop do
y << n
n += 1
end
end
end
That can be used like this:
integer.take(20).inject(&:+)
# => 190

You want a lazy enumerator. In Ruby 2.3.1 (and at least as far back as Ruby 2.2.0), you can make one yourself by mixing in Enumerator::Lazy.
However, if all you want is an infinite stream of integers, you could just use a Range object. For example:
(1 .. Float::INFINITY).take 10
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Related

What does the << operator do in this Ruby function? [duplicate]

This question already has answers here:
Clarification on the Ruby << Operator
(5 answers)
Closed 8 months ago.
I am confused about what the << operator does.
def reconstruct_path(prev, current)
if prev.include? current
p = reconstruct_path(prev, prev[current])
[p] << current
else
current
end
end
Array#<< is known as the "shovel". It pushes "things" into other "things".
Like this in this example:
thing_array = [1, 2, 3, 4, 5]
thing_array << 6
Result: => [1, 2, 3, 4, 5, 6]
So the array thing_array was created with the numbers 1 to 5. By using the shovel it pushes the new entry 6 into the thing_array. It's just a shortcut to make code cleaner and lighter.
I hope that makes sense.

bad value for range (ArgumentError) in ruby

I get the desired output but the interpreter throws an ArgumentError-bad value for range ?
Q)Given an array of integers, for each integer output all integers from 1 to that integer; e.g. if the integer was 5, you would output 1, 2, 3, 4, 5.
Solution:
numbers = [7, 3, 5, 2, 1, 8, 4]
counter = 0
loop do
num = numbers[counter]
(1..num).each do |ele|
puts ele
end
counter += 1
end
I'll let someone else explain why your code is broken, except to say that unless this is a classroom exercise (in which case ask your instructor what the point is), the code is not really idiomatic Ruby. Aside from being more complicated than it needs to be, non-idiomatic Ruby is often harder to debug. One of the following examples will do the right thing when using Ruby 3.0.1, and both are much shorter and less error-prone that manually iterating:
# if you just want to print each item
numbers = [7, 3, 5, 2, 1, 8, 4]
numbers.each { puts _1 }
# if you want to print each slice of length n
numbers.each_index do
next unless _1 > 0
p numbers.slice 0, _1
end
If you need your output in a specific format, that wasn't defined in your original question. Both of these options can be modified to suit whatever output format you're looking for.

How do I iterate through the digits of an integer? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Turning long fixed number to array Ruby
Well, I have to iterate over the digits of a integer in Ruby. Right now I was just splitting it up into an array, and then iterating over that. However I was wondering if there was a faster way to do this?
The shortest solution probably is:
1234.to_s.chars.map(&:to_i)
#=> [1, 2, 3, 4]
A more orthodox mathematical approach:
class Integer
def digits(base: 10)
quotient, remainder = divmod(base)
quotient == 0 ? [remainder] : [*quotient.digits(base: base), remainder]
end
end
0.digits #=> [0]
1234.digits #=> [1, 2, 3, 4]
0x3f.digits(base: 16) #=> [3, 15]
You can use the old trick of modulus/divide by 10, but this won't be measurably faster unless you have huge numbers, and it will give the digits to you backwards:
i = 12345
while i > 0
digit = i % 10
i /= 10
puts digit
end
Output:
5
4
3
2
1
split=->(x, y=[]) {x < 10 ? y.unshift(x) : split.(x/10, y.unshift(x%10))}
split.(1000) #=> [1,0,0,0]
split.(1234) #=> [1,2,3,4]
Ruby has divmod, which will calculate both x%10and x/10 in one go:
class Integer
def split_digits
return [0] if zero?
res = []
quotient = self.abs #take care of negative integers
until quotient.zero? do
quotient, modulus = quotient.divmod(10) #one go!
res.unshift(modulus) #put the new value on the first place, shifting all other values
end
res # done
end
end
p 135.split_digits #=>[1, 3, 5]
For things like Project Euler, where speed is of some importance, this is nice to have. Defining it on Integer causes it to be available on Bignum too.
I like to use enumerators for this purpose:
class Integer
def digits
to_s.each_char.lazy.map(&:to_i)
end
end
This gives you access to all the good Enumerator stuff:
num = 1234567890
# use each to iterate over the digits
num.digits.each do |digit|
p digit
end
# make them into an array
p num.digits.to_a # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
# or take only some digits
p num.digits.take(5) # => [1, 2, 3, 4, 5]
# ...
Try mod by 10 (will give you the last digit), then divide by 10 (will give you the rest of digits), repeat this until you're down to the final digit. Of course, you'll have to reverse the order if you want to go through the digits from left to right.

Ruby Iteration - Trying to match two numbers in a single pass [duplicate]

This question already has answers here:
Ruby array access 2 consecutive(chained) elements at a time
(4 answers)
Closed 3 years ago.
Say I have a an array like:
a = [1, 2, 3, 4, 5, 6]
and I have two variables like this:
b = 3
c = 4
I want to do something like this:
a.each do |i|
if(b = = i) and (c == i.next(I don't think I can do this))
return true
end
end
Any help would be appreciated.
Steve G.
each_cons does what you want:
a = [1, 2, 3, 4, 5, 6]
b=3
c=4
a.each_cons(2){|v1, v2| puts(b == v1 && c == v2)}
# output:
# false
# false
# true
# false
# false
a.each_cons(2).include?([b,c])
Don't use
a.each_slice
To get a series of paired objects.
Use each_cons as suggested by steenslag or glenn mcdonald.
Do you need to do it in a loop, or could you simply track if each variable is a member? of the array in question? Or put them into a hash/set and make sure each key is contained? Or keep the loop, and just keep logical-ORing whether or each var is a member? Or add a members? method to Array, and pass in an array to check against, or...
That should be enough ideas to get you started.

List comprehension in Ruby

To do the equivalent of Python list comprehensions, I'm doing the following:
some_array.select{|x| x % 2 == 0 }.collect{|x| x * 3}
Is there a better way to do this...perhaps with one method call?
How 'bout:
some_array.map {|x| x % 2 == 0 ? x * 3 : nil}.compact
Slightly cleaner, at least to my taste, and according to a quick benchmark test about 15% faster than your version...
If you really want to, you can create an Array#comprehend method like this:
class Array
def comprehend(&block)
return self if block.nil?
self.collect(&block).compact
end
end
some_array = [1, 2, 3, 4, 5, 6]
new_array = some_array.comprehend {|x| x * 3 if x % 2 == 0}
puts new_array
Prints:
6
12
18
I would probably just do it the way you did though.
I made a quick benchmark comparing the three alternatives and map-compact really seems to be the best option.
Performance test (Rails)
require 'test_helper'
require 'performance_test_help'
class ListComprehensionTest < ActionController::PerformanceTest
TEST_ARRAY = (1..100).to_a
def test_map_compact
1000.times do
TEST_ARRAY.map{|x| x % 2 == 0 ? x * 3 : nil}.compact
end
end
def test_select_map
1000.times do
TEST_ARRAY.select{|x| x % 2 == 0 }.map{|x| x * 3}
end
end
def test_inject
1000.times do
TEST_ARRAY.inject([]) {|all, x| all << x*3 if x % 2 == 0; all }
end
end
end
Results
/usr/bin/ruby1.8 -I"lib:test" "/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/performance/list_comprehension_test.rb" -- --benchmark
Loaded suite /usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
ListComprehensionTest#test_inject (1230 ms warmup)
wall_time: 1221 ms
memory: 0.00 KB
objects: 0
gc_runs: 0
gc_time: 0 ms
.ListComprehensionTest#test_map_compact (860 ms warmup)
wall_time: 855 ms
memory: 0.00 KB
objects: 0
gc_runs: 0
gc_time: 0 ms
.ListComprehensionTest#test_select_map (961 ms warmup)
wall_time: 955 ms
memory: 0.00 KB
objects: 0
gc_runs: 0
gc_time: 0 ms
.
Finished in 66.683039 seconds.
15 tests, 0 assertions, 0 failures, 0 errors
There seems to be some confusion amongst Ruby programmers in this thread concerning what list comprehension is. Every single response assumes some preexisting array to transform. But list comprehension's power lies in an array created on the fly with the following syntax:
squares = [x**2 for x in range(10)]
The following would be an analog in Ruby (the only adequate answer in this thread, AFAIC):
a = Array.new(4).map{rand(2**49..2**50)}
In the above case, I'm creating an array of random integers, but the block could contain anything. But this would be a Ruby list comprehension.
I discussed this topic with Rein Henrichs, who tells me that the best performing solution is
map { ... }.compact
This makes good sense because it avoids building intermediate Arrays as with the immutable usage of Enumerable#inject, and it avoids growing the Array, which causes allocation. It's as general as any of the others unless your collection can contain nil elements.
I haven't compared this with
select {...}.map{...}
It's possible that Ruby's C implementation of Enumerable#select is also very good.
I've just published the comprehend gem to RubyGems, which lets you do this:
require 'comprehend'
some_array.comprehend{ |x| x * 3 if x % 2 == 0 }
It's written in C; the array is only traversed once.
An alternative solution that will work in every implementation and run in O(n) instead of O(2n) time is:
some_array.inject([]){|res,x| x % 2 == 0 ? res << 3*x : res}
Enumerable has a grep method whose first argument can be a predicate proc, and whose optional second argument is a mapping function; so the following works:
some_array.grep(proc {|x| x % 2 == 0}) {|x| x*3}
This isn't as readable as a couple of other suggestions (I like anoiaque's simple select.map or histocrat's comprehend gem), but its strengths are that it's already part of the standard library, and is single-pass and doesn't involve creating temporary intermediate arrays, and doesn't require an out-of-bounds value like nil used in the compact-using suggestions.
This is more concise:
[1,2,3,4,5,6].select(&:even?).map{|x| x*3}
[1, 2, 3, 4, 5, 6].collect{|x| x * 3 if x % 2 == 0}.compact
=> [6, 12, 18]
That works for me. It is also clean. Yes, it's the same as map, but I think collect makes the code more understandable.
select(&:even?).map()
actually looks better, after seeing it below.
Ruby 2.7 introduced filter_map which pretty much achieves what you want (map + compact):
some_array.filter_map { |x| x * 3 if x % 2 == 0 }
You can read more about it here.
Like Pedro mentioned, you can fuse together the chained calls to Enumerable#select and Enumerable#map, avoiding a traversal over the selected elements. This is true because Enumerable#select is a specialization of fold or inject. I posted a hasty introduction to the topic at the Ruby subreddit.
Manually fusing Array transformations can be tedious, so maybe someone could play with Robert Gamble's comprehend implementation to make this select/map pattern prettier.
Something like this:
def lazy(collection, &blk)
collection.map{|x| blk.call(x)}.compact
end
Call it:
lazy (1..6){|x| x * 3 if x.even?}
Which returns:
=> [6, 12, 18]
Another solution but perhaps not the best one
some_array.flat_map {|x| x % 2 == 0 ? [x * 3] : [] }
or
some_array.each_with_object([]) {|x, list| x % 2 == 0 ? list.push(x * 3) : nil }
This is one way to approach this:
c = -> x do $*.clear
if x['if'] && x[0] != 'f' .
y = x[0...x.index('for')]
x = x[x.index('for')..-1]
(x.insert(x.index(x.split[3]) + x.split[3].length, " do $* << #{y}")
x.insert(x.length, "end; $*")
eval(x)
$*)
elsif x['if'] && x[0] == 'f'
(x.insert(x.index(x.split[3]) + x.split[3].length, " do $* << x")
x.insert(x.length, "end; $*")
eval(x)
$*)
elsif !x['if'] && x[0] != 'f'
y = x[0...x.index('for')]
x = x[x.index('for')..-1]
(x.insert(x.index(x.split[3]) + x.split[3].length, " do $* << #{y}")
x.insert(x.length, "end; $*")
eval(x)
$*)
else
eval(x.split[3]).to_a
end
end
so basically we are converting a string to proper ruby syntax for loop
then we can use python syntax in a string to do:
c['for x in 1..10']
c['for x in 1..10 if x.even?']
c['x**2 for x in 1..10 if x.even?']
c['x**2 for x in 1..10']
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# [2, 4, 6, 8, 10]
# [4, 16, 36, 64, 100]
# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
or if you don't like the way the string looks or having to use a lambda we could forego the attempt to mirror python syntax and do something like this:
S = [for x in 0...9 do $* << x*2 if x.even? end, $*][1]
# [0, 4, 8, 12, 16]
https://rubygems.org/gems/ruby_list_comprehension
shameless plug for my Ruby List Comprehension gem to allow idiomatic Ruby list comprehensions
$l[for x in 1..10 do x + 2 end] #=> [3, 4, 5 ...]
I think the most list comprehension-esque would be the following:
some_array.select{ |x| x * 3 if x % 2 == 0 }
Since Ruby allows us to place the conditional after the expression, we get syntax similar to the Python version of the list comprehension. Also, since the select method does not include anything that equates to false, all nil values are removed from the resultant list and no call to compact is necessary as would be the case if we had used map or collect instead.

Resources