I'm a ruby newbie, learning to code. I wanted to understand how some of the methods available from the Enumerable module work. So I'm reimplementing them. One challenge was to implement them using recursion. However, I'm running into a problem when trying to implement the Enumerable#Map method using recursion.
This is my code:
class Array
def mymap_recursive(&block)
copy_of_array = dup
new_array = []
return new_array if copy_of_array.empty?
value = copy_of_array.shift
new_array << yield(value)
copy_of_array.mymap_recursive(&block)
end
end
I tried to figure out why it wasn't working so I put
puts "#{new_array}"
at the end of the method. Then in Sublime Text, I did
arr = [2,2,5,5,10]
arr.mymap_recursive {|n| n * n}
After pressing cmd+b, the output I got was:
[100]
[25]
[25]
[4]
[4]
I cannot figure out why its not returning one array with all the values.
Thanks for your help!
What is happening in your code is every time you call mymap_recursive(&block) the new_array is being lost. To solve this you must have a way to maintain the new array that is being built recursively. A simple change to your code is including new_array = [] in your method definition, then passing new array each time. Here would be the code with my changes in place:
class Array
def mymap_recursive(new_array = [], &block)
copy_of_array = self.dup
return new_array if copy_of_array.empty?
value = copy_of_array.shift
new_array << yield(value)
copy_of_array.mymap_recursive(new_array, &block)
end
end
Then when you call
arr = [2,2,5,5,10]
p arr.mymap_recursive {|n| n * n}
#returns
#[4, 4, 25, 25, 100]
If you have any questions over this syntax or anything let me know and I will try my best to explain it!
Another solution which doesn't change the method signature and doesn't mutate any data:
class Array
def mymap_recursive(&block)
if empty?
[]
else
[block.call(first)] + drop(1).mymap_recursive(&block)
end
end
end
Related
I have a method called myFilter that takes in an array, and filters out the elements that don't meet the requirement.
For example.
arr = [4,5,8,9,1,3,6]
answer = myfilter(arr) {|i| i>=5}
this run would return an array with elements 5,8,9,6 since they are all greater than or equal to 5.
How would I preform this? the algorithm is easy, but I don't understand how we take in that condition.
Thank you.
I take for granted you don't want to use select method or similar but you want to understand how blocks work.
def my_filter(arr)
if block_given?
result = []
arr.each { |element| result.push(element) if yield element } # here you use the block passed to this method and execute it with the current element using yield
result
else
arr
end
end
The idiomatic way would be:
def my_filter(arr)
return enum_for(:my_filter, arr) unless block_given?
arr.each_with_object([]) do |e, acc|
acc << e if yield e
end
end
More info on Enumerator::Lazy#enum_for.
you can do
def my_filter(arr, &block)
arr.select(&block)
end
then call
my_filter([1, 2, 3]) { |e| e > 2 }
=> [3]
but instead you can just call select with a block directly :)
Is there a way to return the new array?
I try to return the array of squared value [1, 4, 9] but it keeps returning [1, 2, 3] (the original array) Here is my code:
def square_array(array)
array.each do |number|
number *= number
puts number
end
end
square_array([1, 2, 3])
A much simpler version that does what you want:
def square_array(array)
array.map do |number|
number*number
end
end
The problem with your code is that when you assign something to number, you're just assigning a value to a local variable, not some magic reference into an array.
Try this out:
Using Each method
def square_array(array)
temp = []
array.each do |number|
temp << (number * number)
end
temp
end
When writing semantic ruby, it is best to use proper enumerable methods. There is no need for the temporary variable in this case... we can use the #map method to return a new array that is the result of applying a function to each value in turn. This is a core concept of the functional programming paradigm:
def square_array numbers
numbers.map { |x| x ** 2 }
end
I fund a way, I just needed to push the result in a new array
def square_array(array)
new_array = []
array.each do |num|
squared_num = num ** 2
new_array.push(squared_num)
end
return new_array
end
What is the idiomatic Ruby way to write this code?
Given an array, I would like to iterate through each element of that array, but skip the first one. I want to do this without allocating a new array.
Here are two ways I've come up with, but neither feels particularly elegant.
This works but seems way too verbose:
arr.each_with_index do |elem, i|
next if i.zero? # skip the first
...
end
This works but allocates a new array:
arr[1..-1].each { ... }
Edit/clarification: I'd like to avoid allocating a second array. Originally I said I wanted to avoid "copying" the array, which was confusing.
Using the internal enumerator is certainly more intuitive, and you can do this fairly elegantly like so:
class Array
def each_after(n)
each_with_index do |elem, i|
yield elem if i >= n
end
end
end
And now:
arr.each_after(1) do |elem|
...
end
I want to do this without creating a copy of the array.
1) Internal iterator:
arr = [1, 2, 3]
start_index = 1
(start_index...arr.size).each do |i|
puts arr[i]
end
--output:--
2
3
2) External iterator:
arr = [1, 2, 3]
e = arr.each
e.next
loop do
puts e.next
end
--output:--
2
3
OK, maybe this is bad form to answer my own question. But I've been racking my brain on this and poring over the Enumerable docs, and I think I've found a good solution:
arr.lazy.drop(1).each { ... }
Here's proof that it works :-)
>> [1,2,3].lazy.drop(1).each { |e| puts e }
2
3
Concise: yes. Idiomatic Ruby… maybe? What do you think?
There is a method called all? in Enumerable.
I'm trying to learn all the methods of Enumberable's library by writing them myself.
This is what I've come up so far for the all? method. I sorta understand it but I got stumped when trying to pass initialized values to my method.
EDIT for the record, I'm aware that enum method that I have is not the right way ie, it's hard-coded array. This is for self-learning purposes. I'm just trying to figure out how to pass the initialized values to my all? method. That's why I wrote enum in the first place, to see that it is working for sure. Please don't take this class as a literal gospel. Thank you.
class LearningMethods
def initialize(values)
#values = values
end
def enum
array = [10, 3, 5]
end
def all?(a)
yield(a)
end
end
c = LearningMethods.new([10, 3, 5])
p c.enum.all? {|x| x >= 3 } #this works
p c.all?(10) { |x| x >= 3 } #this works
p c.all?(#values) { |x| x >= 3 } #this doesn't work. Why not? And how do I pass the initialized values?
I'm not sure why you need enum at all? Enumerable is a module included in array, so if you're not familiar with this I recommend you read about "modules and mix-ins" in Ruby.
all? works simply by passing EACH of the array elements to the block. If there is ANY element (at least 1) for which the block returns false, then all? evaluates to false. Try analyzing this code:
class MyAllImplementation
def initialize(array)
#array = array
end
def my_all?
#array.each do |element| # for each element of the array
return true unless block_given? # this makes sure our program doesn't crash if we don't give my_all? a block.
true_false = yield(element) # pass that element to the block
return false unless true_false # if for ANY element the block evaluates to false, return false
end
return true # Hooray! The loop which went over each element of our array ended, and none evaluted to false, that means all elements must have been true for the block.
end
end
a = MyAllImplementation.new([1,2,3])
p a.my_all? { |x| x > 0 } #=> true
p a.my_all? { |x| x > 1 } # false, because 1 is not bigger than 1, it's equal to 1
If I want a part of an array I can use [] or split:
arr = [1,2,3,4,5]
arr[1..3]
=> [2, 3, 4]
But is there a 'general' version of []? Can I apply it to any Enumerator?
enum = arr.each
enum.xxx_method(1..3) # is equal to arr[1..3].each
Of course you can use arr[1..3] directly. But I'm seeking a general way to handle any enumerator.
If you have an enumerator, you can count on Enumerable methods drop and take:
# abstract if necessary as enum_slice(range)
enumerator.drop(2).take(3)
If that enumerator is an array you don't need to traverse it, check the method Array#lazy_slice that I asked to be added to enumerable_lazy in relation with your previous question:
require 'enumerable/lazy'
class Array
def lazy_slice(range)
Enumerator.new do |yielder|
range.each do |index|
yielder << self[index]
end
end.lazy
end
end
some_big_array = (0..10000).to_a # fake array, it won't generally be a range
p some_big_array.lazy_slice(9995..10000).map { |x| 2*x }.to_a
#=> [19990, 19992, 19994, 19996, 19998, 20000]