Ruby Blocks (Yield)

I'm just getting started with Ruby, I'm pretty up to date with my Bloc course, but now I'm stuck with an exercise dealing with harvest and blocks (which I find the hardest concept so far when it comes to learning ruby).

Here are the required specifications in plain text format:

  • Define new_map method
  • It should take an array as an argument and return a new array, modified according to the instructions passed as a block.
  • You cannot use .map or .map! Methods
  • However, feel free to use each in the method
  • You need to store the return value from each block call in a new array
  • It should display any object

Here are the RSpecs to follow:

describe "new_map" do
  it "should not call map or map!" do
    a = [1, 2, 3]
    a.stub(:map) { '' }
    a.stub(:map!) { '' }

    expect( new_map(a) { |i| i + 1 } ).to eq([2, 3, 4])
  end

  it "should map any object" do
    a = [1, "two", :three]
    expect( new_map(a) { |i| i.class } ).to eq([Fixnum, String, Symbol])
  end
end

      


Here is the original def method they gave me to start with:

def new_map(array)
  new_array = []
  array.each do |item|
    # invoke the block, and add its return value to the new array
  end
end

      


Then here is my current code (Updated):

def new_map(a)
  new_array = []
  a.each do |item|
    # invoke the block, and add its return value to the new array.
    yield(item, new_array)
  end
end

a = [2, 3, 4]

new_map(a) do |i, e|
  e << i
end

      


Finally, when I post the current code I just listed, I get the following errors (Updated):

new_map should not be named map or map! (Incomplete)

    expected: [2, 3, 4]
     got: [1, 2, 3]

(compared using ==)
exercise_spec.rb:9:in `block (2 levels) in <top (required)>'

      


new_map should map any object (INCOMPLETE)

expected: [Fixnum, String, Symbol]
     got: [1, "two", :three]

(compared using ==)

exercise_spec.rb:14:in `block (2 levels) in <top (required)>'

      

+3


source to share


3 answers


What you don't understand is that yield can make a difference. The last statement executed in the block is the return value.

This way you can get the results from each yield call and add it to the resulting array.



We then get the resulting array as the return value from your method new_map

.

def new_map(a)
  new_array = []
  a.each do |item|
    # invoke the block, and add its return value to the new array.
    new_array << yield(item)
  end
  new_array
end

      

+1


source


Try the following:

def new_map(a)
  new_array = []
  a.each do |item|
    # # invoke the block, and add its return value to the new array.
    puts yield(item) # just experimenting
  end
end

new_map(a) { |i| i + 1 }

      

This element yield

simply takes each element from the array and runs it through the block. This experimental code simply prints the results; they must be collected in an array. Not difficult:



def new_map(a)
  new_array = []
  a.each do |item|
    new_array = []
    # invoke the block, and add its return value to the new array.
    new_array << yield(item)
  end
end

      

This will not pass all tests, but the last step should be doable.

+1


source


new_array

is created in the definition new_map

, which is a different "lexical scope" than the block you write when you call new_map

. Basically, the code in the method new_map

can see new_array

, but the code in your block cannot. One way to fix this problem is by looking at methods Enumerable

inject

or methods each_with_object

that might work instead each

in your method new_map

.

0


source







All Articles