I'm reading The Well-Grounded Rubyist and have come across an extra credit challenge to which there is no answer.
class Array
def my_each
c = 0
until c == size
yield(self[c])
c += 1
end
self
end
end
An example is given of creating a my_each with my_times
class Array
def my_each
size.my_times do |i|
yield self[i]
end
self
end
end
With the point that many of Ruby's iterators are built on top of each and not the other way around.
Given the above my_each, how could I use it in an implementation of my_times?
To make it clear, an example of a my_times implementation was given before:
class Integer
def my_times
c = 0
until c == self
yield(c)
c += 1
end
self
end
end
5.my_times { |e| puts "The block just got handed #{e}." }
So it would seem that the question most certainly implies using my_each in an implementation of my_times.
To implement my_times using my_each, all you need to do is call my_each on an array that looks like [0, 1, ..., (x - 1)], where x is self (the Integer):
class Integer
def my_times(&block)
(0...self).to_a.my_each do |n|
yield n
end
self
end
end
P.S. If you defined my_each on Enumerable instead of Array (like the "real" each), you could remove to_a from the third line above and iterate directly over the Range, instead of converting the Range to an Array first.
In order to implement my_times we need an array to send my_each message to. At that point of the book I don't think range is covered so I implemented without using a range. Here is the solution:
require_relative "my_each"
class Integer
def my_times
array = Array.new(self)
c = 0
array.my_each do
array[c] = c
yield(c)
c += 1
end
self
end
end
Edit: I just noticed Jordan used ... instead of .. which generates the correct output; See this answer for more detail on the difference for ranges. I've updated my answer below.
My account is too new and I can't comment on Jordan's solution; I see this was posted about a year ago but I am currently reading through The Well-Grounded Rubyist and wanted to comment on the solution.
I had approached it the same in a similar way as Jordan but found that the output is off compared to; The Well-Grounded Rubyist implementation of my_times which produces:
puts 5.my_times { |i| puts "I'm on iteration # {i}!" }
I'm on iteration 0!
I'm on iteration 1!
I'm on iteration 2!
I'm on iteration 3!
I'm on iteration 4!
Jordan's solution outputs:
puts 5.my_times { |i| puts "I'm on iteration # {i}!" }
I'm on iteration 0!
I'm on iteration 1!
I'm on iteration 2!
I'm on iteration 3!
I'm on iteration 4!
I'm on iteration 5!
I used a magic number to match The Well-Grounded Rubyist output [See Jordan's solution, using ... instead of .. which removes the need for the magic number]
class Integer
def my_times
(0..(self-1)).to_a.my_each do |n|
yield n
end
self
end
end
I shortened dwyd's implementation to supply a block rather than using the do..end.
class Integer
def my_times
(0...self).to_a.my_each { |i| yield i }
end
end
Also, I don't think you need to do self-1.
Related
Total beginner here, so I apologize if a) this question isn't appropriate or b) I haven't asked it properly.
I'm working on simple practice problems in Ruby and I noticed that while I arrived at a solution that works, when my solution runs in a visualizer, it gives premature returns for the array. Is this problematic? I'm also wondering if there's any reason (stylistically, conceptually, etc.) why you would want to use a while-loop vs. a for-loop with range for a problem like this or fizzbuzz.
Thank you for any help/advice!
The practice problem is:
# Write a method which collects all numbers between small_num and big_num into
an array. Ex: range(2, 5) => [2, 3, 4, 5]
My solution:
def range(small_num, big_num)
arr = []
(small_num..big_num).each do |num|
arr.push(num)
end
return arr
end
The provided solution:
def range(small_num, big_num)
collection = []
i = small_num
while i <= big_num
collection << i
i += 1
end
collection
end
Here's a simplified version of your code:
def range(small_num, big_num)
arr = [ ]
(small_num..big_num).each do |num|
arr << num
end
arr
end
Where the << or push function does technically have a return value, and that return value is the modified array. This is just how Ruby works. Every method must return something even if that something is "nothing" in the form of nil. As with everything in Ruby even nil is an object.
You're not obligated to use the return values, though if you did want to you could. Here's a version with inject:
def range(small_num, big_num)
(small_num..big_num).inject([ ]) do |arr, num|
arr << num
end
end
Where the inject method takes the return value of each block and feeds it in as the "seed" for the next round. As << returns the array this makes it very convenient to chain.
The most minimal version is, of course:
def range(small_num, big_num)
(small_num..big_num).to_a
end
Or as Sagar points out, using the splat operator:
def range(small_num, big_num)
[*small_num..big_num]
end
Where when you splat something you're in effect flattening those values into the array instead of storing them in a sub-array.
This is a description of a code kata that I'm working on for code wars. The aim of the kata is to accomplish this:
The aim of this Kata is to modify the Fixnum class to give it the palindrome_below method. This method returns all numbers from and including 1 up to but not including itself that are palindromes for a given base.
For example in base 2 (binary)
1 = "1"
2 = "10"
3 = "11"
4 = "100"
Therefore 1 and 3 are palindromes in base two and the method should return the following.
5.palindrome_below(2)
=> [1, 3]
Here is the code that I wrote so far for this kata:
class Fixnum
def self.palindrome_below(binary)
palindrome_match = []
until self == 0
if to_s(binary) == to_s(binary).reverse
palindrome_match << self
self -= 1
end
end
palindrome_match
end
end
I tried to decrease self by 1. Sublime is telling me that I'm not able to decrease the value of self but I need to reduce self. Because this is a class method, I need to modify self.
This is what I tried as a work around:
class Fixnum
def self.palindrome_below(binary)
palindrome_match = []
self_placeholder = self
until self_placeholder == 0
if self_placeholder.to_s(binary) == self_placeholder.to_s(binary).reverse
palindrome_match << self_placeholder
self_placeholder -= 1
end
end
palindrome_match
end
end
This time, I placed self in a wrapper variable so I could modify it. When I try this, it says that there is an undefined method called palindrome_below. Doing this implementation should have monkey patched Fixnum. I'm not sure what I'm doing wrong. Can someone point me in the right direction?
A Working Solution (based your second attempt above):
class Fixnum
def palindrome_below(base)
palindrome_match = []
num = self - 1
until num == 0
if num.to_s(base) == num.to_s(base).reverse
palindrome_match << num
end
num -= 1
end
palindrome_match.reverse
end
end
What I changed:
You were right in adding a self_placeholder -- I named this variable num. In Ruby, Fixnums are immutable, so you can't change the value of the particular Fixnum itself.
I subtracted 1 from num right at the beginning, so as to avoid including the number itself in the result array
palindrome_below(base) needs to be an instance method. You very much care about the value of the specific instance of the Fixnum class (ie., the value of the number).
You need to subtract 1 from num outside your if statement.
I reversed the palindrome_match array so that it returns in the proper ascending order.
A Far Superior Solution (courtesy of #CarySwoveland's comment above).
class Fixnum
def palindrome_below(base)
1.upto(self-1).select { |num| num.to_s(base) == num.to_s(base).reverse }
end
end
Can you help me understand what this class does and how we can make use of it?
class Integer
def myt
c=0
until c == self
yield(c)
c+=1
end
self
end
end
Thank you.
x = Integer.new
x.myt
I tried to test it but it doesn't work. Error is: "no block given (yield)"
Also, in my book it says to test like this:
5.myt (|| puts "I'm on iteration #{i}! "} but it also gives an error - not sure why or what this line of code means.
allonhadaya and PNY did a good job explaining the purpose (enumeration) of the myt method.
Regarding your two questions mentioned in the title:
1.) What does 'c == self' do?
The '==' operator checks whether the integer c and Integer object you instantiate, are equal in value. If they are, the expression evaluates to true.
2.) What does 'yield' do?
The 'yield' statement passes control from the current method to a block which has been provided to the method. Blocks are ruby's implementation of a closure which, simple put, means that a method can be "extended" by calling the method with a block of additional code as long as the method supports a block (ie. incorporates yield statements)
The method seems to be a times implementation.
Basically 5.times { |i| puts i } and 5.myt { |i| puts i } will do exactly the same thing.
First, it sets a counter to 0, c = 0. Then you have a conditional where it checks if c is equal with self which will always be the integer attached to the method myt. It, then yields the counter and return self when is done.
Looks like it enumerates the values between zero inclusively and self exclusively.
allon#ahadaya:~$ irb
irb(main):001:0> class Integer
irb(main):002:1> def myt
irb(main):003:2> c=0
irb(main):004:2> until c == self
irb(main):005:3> yield(c)
irb(main):006:3> c+=1
irb(main):007:3> end
irb(main):008:2> self
irb(main):009:2> end
irb(main):010:1> end
=> nil
irb(main):011:0> 5.myt { |i| puts i }
0
1
2
3
4
=> 5
irb(main):012:0>
Using the example your book gave --
5.myt {|i| puts "I'm on iteration #{i}! "}
#You were missing an object in the pipes and a curly bracket before the pipes (not parentheses)
Allows you to see the internal workings of your myt method. Initializing variable c with a value of 0 the method executes an until look until the condition "c == self" is satisfied. Self references the object, here 5, which the method is acting on.
Therefore ...
def myt
until c == 5 #Until this is true
yield(c) #Do this .. here yield will do whatever the block specified
c+=1 #Increment on each iteration the value of variable c by 1
end #closing the until loop
self #return self
end
The yield within the method passes control from your method to the parameter, a block, back to the method.
Yield therefore allows you to build methods which can have similar patterns but with block you customize it to do your particular need.
If instead of putting each number maybe all you want to do is put the odd integers between 0 and the integer you call the method on --
5.myt {|i| puts i if i.odd?} # returns I am odd: 1 and I am odd: 3
I would suggest that you write your own blocks here to see how yield works and how you can keep the same method but pass in different blocks and create different method outputs!
I am toying around with Ruby to learn the language. Currently I'm trying to wrap my head around the concept of fibers. According to this answer, they are fairly often used for creating (infinite) external enumerators. On the other hand, this seems to overlap with the concept of so called explicit enumerators.
Say, I want to write a code snippet that fires consecutive prime numbers (yes, the following algorithm has a runtime of O(scary)). I can implement it by using fibers:
prime_fiber = Fiber.new do
primes = [2]
Fiber.yield 2
current = 1
loop do
current += 2
unless primes.find {|value| (current % value) == 0}
Fiber.yield current
primes << current
end
end
end
ARGV[0].to_i.times {print "#{prime_fiber.resume}, "}
This does not emit an enumerator object by itself, although it is not difficult to create one out of it. In contrast, I can also utilize an explicitly defined enumerator, which has the added benefit of already being an enumerator object:
prime_enum = Enumerator.new do |yielder|
primes = [2]
yielder.yield 2
current = 1
loop do
current += 2
unless primes.find {|value| (current % value) == 0}
yielder.yield current
primes << current
end
end
end
ARGV[0].to_i.times {print "#{prime_enum.next}, "}
# I could also write:
# p prime_enum.first(ARGV[0].to_i)
Both methods allow me to implement some sort of co-routines and they seem to be interchangeable to me. So when do I prefer one over the other? Is there some commonly agreed practice? I find it difficult to get all those idioms in my head, so I apologize in advance if this is considered a dumb question.
I would use Enumerator, it allows you to use take, take_while, even each if your sequence is finite. While Fiber is designed for light weight concurrency and is pretty limited as enumerator.
prime_enum.take(ARGV[0].to_i).each { |x| puts x }
or
prime_enum.take_while { |x| x < ARGV[0].to_i }.each { |x| puts x }
this is the question
Shuffle. Now that you’ve finished your
new sorting algorithm, how about the
opposite? Write a shuffle method that
takes an array and returns a totally
shuffled version. As always, you’ll
want to test it, but testing this one
is trickier: How can you test to make
sure you are getting a perfect
shuffle? What would you even say a
perfect shuffle would be? Now test for
it.
This is my code answer:
def shuffle arr
x = arr.length
while x != 0
new_arr = []
rand_arr = (rand(x))
x--
new_arr.push rand_arr
arr.pop rand_arr
end
new_arr
end
puts (shuffle ([1,2,3]))
What are my mistakes? Why doesn't this code work?
Here's a far more Rubyish version:
class Array
def shuffle!
size.downto(1) { |n| push delete_at(rand(n)) }
self
end
end
puts [1,2,3].shuffle!
Here's a more concise way of writing it:
def shuffle(arr)
new_arr = []
while (arr.any?) do
new_arr << arr.delete_at(rand(arr.length))
end
new_arr
end
And some tests:
5.times do
puts shuffle((1..5).to_a).join(',')
end
>> 4,2,1,3,5
>> 3,2,1,4,5
>> 4,2,5,1,3
>> 5,2,1,4,3
>> 4,3,1,5,2
Beside minor other errors you seems not to understand what pop and push are doing (taking or adding some items from the end of the array).
You are probably trying to write something like below.
def shuffle arr
x = arr.length
new_arr = []
while x != 0
randpos = rand(x)
x = x-1
item = arr[randpos]
new_arr.push item
arr[randpos] = arr[x]
arr.pop
end
new_arr
end
puts (shuffle ([1,2,3]))
You're getting your indexes mixed up with your values. When you do new_arr.push rand_arr, you're putting whatever random index you came up with as a value on the end of new_arr. What you meant to do is new_arr.push arr[rand_arr], where arr[rand_arr] is the value at the index rand_arr in arr.
Ruby 1.8.7 and 1.9.2 have a built-in Array#shuffle method.
A variant of Mark Thomas's answer. His algorithm can be quite slow with a large array, due to delete operation performance.
class Array
def shuffle!
size.downto(1) do |n|
index=rand(n)
# swap elements at index and the end
self[index], self[size-1] = self[size-1],self[index]
end
self
end
end
puts [1,2,3].shuffle!
This algorithm is O(size), while Mark's algorithm is O(size^2). On my computer, Mark's answer takes 400 seconds to shuffle an array of 1,000,000 elements on my machine, versus 0.5 seconds with my method.