0
[1,2,3,4,5,6,7].delete_if{|i| i < 4 }

For example, in the above, why do you need to put |i| before i < 4?

I'm new to Ruby programming and the purpose of this element escapes me.

1
  • Found a decent explanation on codecademy that made it click for me: "The variable name between | | can be anything you like: it's just a placeholder for each element of the object you're using .each on." Commented Sep 14, 2013 at 18:27

4 Answers 4

4

This is very basic Ruby syntax for a block. A block can sometimes take parameters which are given between the bars |. In your case:

[1,2,3,4,5,6,7].delete_if { |i| i < 4 }

The delete_if method for the type Array accepts a block as a parameter. When the bock is given, the block accepts the array element as a parameter. So it iterates i over each value within the array in this case. More specifically, an element will be deleted from the array if that element is < 4. The result will be:

[4,5,6,7]

You'll often see documentation for methods for Ruby types which say, for example:

delete_if { |item| block } -> Array

Which means that the method accepts a block with a parameter, the block being some code that uses the parameter, and the output being another array. The method's description explains more detail in the documentation (e.g., Ruby Array).

I recommend reading some Ruby getting started information online or a good introductory book which will explain this in more detail.

Sign up to request clarification or add additional context in comments.

3 Comments

I'm working on my third or fourth beginners (rubymonk) tutorial and I swear I'm still so confused. Thank you for the answer though. I hope my question wasn't too basic for this place.
@JustusDannyEapen no problem. Once you see how a couple of these basic concepts in Ruby works, it will all become obvious. ;)
@JustusDannyEapen some tutorials do things a bit by wrote rather than explain the principles in Ruby's object design. (Although I haven't examined the Rubymonk tutorials.) A book that really helped me initially was by David Black, "Ruby for Rails: Ruby Techniques for Rails Developers". It may no longer be up to date with the latest Ruby/Rails revisions, but it explains the basis of Ruby. You want to find something like that.
3

You have to put i there for the same reason you would put i in the first line here:

def plus_one(i)
  return i + 1
end

You have to name your method argument, which you later use as a local variable in the method.

Ruby blocks are similar to methods, they can also receive arguments, and syntax for declaring them is slightly different: enclosing them in | |.

Comments

1

I've redone my answer, even though the OP's question has already been answered, because I thought of a new way to explain this that may help future SO users with the same question.

From high school algebra, you should remember functions like this: f(x) = x + 1.

Imagine putting curly braces around the x + 1: f(x) = { x + 1 }

Then move the (x) to inside the curly braces: f = {(x) x + 1 }

And then get rid of the name f: {(x) x + 1 }. This makes it an "anonymous function," i.e. a "lambda."

Here's the problem: The braces could contain arbitrary statements, which may themselves use parentheses: (x + 1) * 4. So how would Ruby know that the (x) is supposed to be an argument to the function, and not an expression to execute? Some other syntax had to be used. Hence the vertical bars: |x|. (At least I assume that was the thought process).

So {|i| i > 4 } is just like f(i) = i > 4, except that it has no name and is not defined in advance, so the parameter has to be defined "inside" the function itself, rather than being outside attached to the name.

Array#delete_if expects such a function (called a "block" when it's used like this) and knows what to do with it. It passes each member of the array [1,2,3,4,5,6,7] into the block as the argument i to see whether i > 4 is true for that member. It's equivalent to doing something like this:

def greater_than_four(x)
  x > 4
end
arr = [1,2,3,4,5,6,7]
arr.each do |el|
  arr.delete(el) if greater_than_four(el)
end

You could avoid defining the greater_than_four method in advance by defining a lambda on the fly like this:

arr = [1,2,3,4,5,6,7]
arr.each do |el|
  arr.delete(el) if lambda{|i| i > 4}.call(el)
end

But since Array#delete_if already expects a block, and already knows to call it on each element, you can save yourself a whole lot of code:

[1,2,3,4,5,6,7].delete_if{|i| i < 4 }

2 Comments

If all answers were put into the context of high school math, this site might be a better place. Thanks a lot man I'm still trying to figure this all out.
Glad I could help! I was confused about exactly the same thing when I first started. Make sure you take the time to learn about Procs and lambdas (lambdas are types of Procs in Ruby). It's one of those things that seems difficult at first but once you learn it it's really useful.
0

The parameter which you are passing to the delete_if method is a block and the thing inside the parameter you pass to the block.

Think of the block as a method of sorts. The delete_if method iterates over the block and passes the current item as the parameter i to the block. If the condition evaluates to true then that element gets deleted.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.