2

How can I auto-increment a variable so each time it is used, it is incremented by one, starting with 0?

For example:

i = i+1 || 0 

arr[i] = "foo"
arr[i] = "bar"
arr[i] = "foobar"

arr #=> ["foo","bar","foobar"]

I'm getting a NoMethodError undefined method '+' for nil:NilClass

2
  • 2
    Is your intent to actually use i as an array index for assignment as in your example? If it is, why not just use the << array append operator to fill the array? Commented Dec 31, 2013 at 2:18
  • 1
    Don't write code like i = i+1 || 0. It's not idiomatic, nor is it particularly readable or maintainable. Instead do the normal thing and assign i = 0, then use i += 1 wherever you need it to increment. Commented Dec 31, 2013 at 3:24

4 Answers 4

5

A variable is just a name. It doesn't have behavior. If you want behavior, use a method:

def i
  @i ||= -1
  @i += 1
end

arr = []

arr[i] = 'foo'
arr[i] = 'bar'
arr[i] = 'foobar'

arr #=> ['foo', 'bar', 'foobar']

Alternatively:

_i = -1

define_method(:i) do
  _i += 1
end

arr = []

arr[i] = 'foo'
arr[i] = 'bar'
arr[i] = 'foobar'

arr #=> ['foo', 'bar', 'foobar']

But really, what you have is just a very convoluted way of saying

arr = %w[foo bar foobar]

which is much clearer.

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

1 Comment

Hmm, I don't think define_method is available unless you are calling it on a class or module. I just tried it out here in IRB. Also, if it does work it would affect the object you called it on.
2

You can't. There is no way to associate variables with behaviors — in fact, doing anything with local variables besides just reading and setting them in the obvious way is nigh impossible in standard Ruby — and integers cannot change value.

However, if you are really looking to do something like this with an arrays, you can just use the << operator to push to the end of the array:

arr = []
arr << "foo"
arr << "bar"
arr << "foobar"

arr #=> ["foo","bar","foobar"]

Comments

2

The other answers are pretty good. I would just like to add a few ways that I would implement it.

You could use a Proc:

i = -1
next_i = Proc.new { i += 1 }
next_i.call  # => 0
next_i.call  # => 1

You could use an Enumerator:

ids = Enumerator.new { |y| i = -1; loop { y << (i+=1) } }
ids.next     # => 0
ids.next     # => 1

If it makes sense in your application for the ids to come from some larger object, you could define a method in that object like this:

def next_id
  @i ||= -1
  @i += 1
end

Comments

1

This seems like what you're trying to do, but I wouldn't recommend it:

ary = []
i = -1
ary[i += 1] = 'foo'
ary[i += 1] = 'bar'
ary # => ["foo", "bar"]

Instead, do the idiomatic and expected thing and assign to an array one of these ways:

ary = ['foo', 'bar']
ary = %w[foo bar]
ary # => ["foo", "bar"]

Or, use the << operator to append on the fly, as the other answers recommend.

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.