How to limit each `do` loop by a different variable - ruby

I'm working on a bot. I have ships, each put in an array my_ships. Each ship is given an id when it is created independent of who created it, and each ship can be destroyed. This is the first array:
ship = Ship.new(
player_id, id,
Float(x),
Float(y),
Integer(hp),
Integer(status),
Integer(progress),
Integer(planet)
)
Each iteration sends commands. I run into timeout issues. I only have enough time to run ~100.
How do I limit my each loop to run only 100 times?
my_ships(0, 100).each do |ship|
gets me less ships to use as some are destroyed, and they are ordered by their id.

Assuming this isn't in some sort of database, where you should use a database query to select and limit (since nothing db-related is tagged), you can make use of Enumerable#lazy (this is a method on array's as well, since array's are Enumerable). You'll first want to select only the ships that are not destroyed and then take only the first 100 of those:
my_ships.lazy.select do |ship|
# Some logic to see if a ship is allowed to be iterated
end.first(100).each do |ship|
# your loop that runs commands
end
if it makes more sense, you can use reject instead of select:
my_ships.lazy.reject do |ship|
# Some logic to see if a ship should not be iterated
end.first(100).each do |ship|
# your loop that runs commands
end
to see a little clearer what this will do for you, consider the following example:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
numbers.lazy.select do |number|
puts "running check for #{number}"
number.even?
end.first(2).each do |number|
puts "doing something with #{number}"
end
# running check for 1
# running check for 2
# running check for 3
# running check for 4
# doing something with 2
# doing something with 4
So in this example, I want to run a loop for the first 2 even numbers...if I just take the first 2 numbers, I get 1 even and 1 odd; I also don't want to loop through the entire list, because the check for is this even? might be expensive (it's not, but your check could be), or your list could be large and you only need a few items. This loops through just enough to get me the first 2 numbers that match my criteria and then let's me run my loop on them.

As suggested in the comments by #user3309314 you may wish to use next.
arr = (1..100).to_a
enum = arr.to_enum
hun = loop.with_object [] do |_,o|
if o.size == 10
break o
elsif enum.peek.even?
o << enum.next
else
enum.next
end
end
hun #=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
This loop goes through each element of arr via enumeration and adds it to another array o if it satisfies the condition even?. The loop breaks when o.size == 10.
Might be easier to create a more explicit enumerator then take from that. That way you can vary how many elements you need enum.take(8) gets you the first 8 elements etc.
enum = Enumerator.new do |y|
arr = (1..100).to_a
enum = arr.to_enum
loop { enum.peek.even? ? y << enum.next : enum.next }
end
enum.take 10 #=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

Related

Why is my filter method not removing some elements that should be removed?

I am trying to create a method called filer_out! that takes in an array and a proc, and returns the same array but with every element that returns true when it is run through the proc, with the caveat being we can't use Array#reject!
I wrote this:
def filter_out!(array, &prc)
array.each { |el| array.delete(el) if prc.call(el)}
end
arr_2 = [1, 7, 3, 5 ]
filter_out!(arr_2) { |x| x.odd? }
p arr_2
but when I run the code, what prints out is:
[7, 5]
even though the answer should be:
[]
Upon review of the solution I see Array#uniq was used first:
def filter_out!(array, &prc)
array.uniq.each { |el| array.delete(el) if prc.call(el) }
end
arr_2 = [1, 7, 3, 5 ]
filter_out!(arr_2) { |x| x.odd? }
p arr_2
and the correct output was displayed:
[]
So I guess what my question is, why do you have to use Array#uniq in order to get the correct solution?
thanks for your help!
The problem here is the method delete modify the original array. Here the deal if you put some information out:
def filter_out!(array, &prc)
array.each.with_index do |el, i|
p "Current index #{i}"
p "Current array #{array}"
p "Current element #{el}"
array.delete(el) if prc.call(el)
end
end
arr_2 = [1, 7, 3, 5 ]
filter_out!(arr_2) { |x| x.odd? }
# Output:
#"Current index 0"
# "Current array [1, 7, 3, 5]"
# "Current element 1"
# "Current index 1"
# "Current array [7, 3, 5]"
# "Current element 3"
Explain:
The first time, the element is 1, after it's deleted the array is [7, 3, 5]
The second time, index in the iteration is 1, it gets the current element with this index in the current array, in this case, is 3 not 7 and delete it, after deleting the array is [3, 5]
After two times it stops iteration because the current index is out of range of the current array
By using uniq you get the right result because array.uniq it creates a copy of the original array when the original array is modified, it still iteration as expect.
Traversing an array uses an internal "cursor" of some kind that points to the current element, e.g.:
[ 1, 7, 3, 5 ] # 1st step
# ^
[ 1, 7, 3, 5 ] # 2nd step (increment cursor)
# ^
# etc.
If you remove the current element during iteration, the cursor immediately points to the next element, thus skiping an element when it gets incremented on the next turn:
[ 1, 7, 3, 5 ] # 1st step
# ^
[ 7, 3, 5 ] # 1nd step (remove element under cursor)
# ^
[ 7, 3, 5 ] # 2nd step (increment cursor)
# ^
[ 7, 5 ] # 2nd step (remove element under cursor)
# ^
# done
A typical work-around is to iterate the array in reverse order, i.e.:
[ 1, 7, 3, 5 ] # 1st step
# ^
[ 1, 7, 3 ] # 1nd step (remove element under cursor)
# ^
[ 1, 7, 3 ] # 2nd step (decrement cursor)
# ^
[ 1, 7 ] # 2nd step (remove element under cursor)
# ^
# etc.
Note that the cursor might be out of bounds in this algorithm, so you have to be careful in that regard.
The above as Ruby code:
def filter_out!(array)
(array.size - 1).downto(0) do |i|
array.delete_at(i) if yield array[i]
end
end
As a general rule, not just for this question, and not just for Ruby, it is never a good idea to mutate a collection while you are iterating over it. Just don't do that. Ever.
Actually, personally, I just think you should avoid any mutation at all, as far as feasible and sensible, but that might be a tad extreme.
Your code is also committing another cardinal sin: never mutate an argument. Ever. You should only use arguments to compute the result, you should never mutate them. That is hugely surprising to anyone who calls your method, and in programming, surprises are dangerous. They lead to bugs and security holes.
Lastly, you are using the bang ! naming convention wrong. The bang is used to mark the "more surprising" of a pair of methods. You should only have a filter_out! method if you also have a filter_out method. And speaking of style, indentation in Ruby is 2 spaces, not 4, as per standard community coding style.
Okay, having said that, let's look at what happens in your code.
Here is the relevant part of the implementation of Array#each from the Rubinius Ruby implementation, defined in core/array.rb#L62-L77:
def each
i = #start
total = i + #total
tuple = #tuple
while i < total
yield tuple.at(i)
i += 1
end
end
As you can see, it is just a simple while loop incrementing the index every time. Other Ruby implementations are similar, e.g. here is a simplified version of JRuby's implementation in core/src/main/java/org/jruby/RubyArray.java#L1805-L1818:
public IRubyObject each(ThreadContext context, Block block) {
for (int i = 0; i < size(); i++) {
block.yield(context, eltOk(i));
}
}
Again, just a simple index loop.
In your case, we are starting with an array, whose backing store looks like this:
1 7 3 5
On the first iteration of the each, the iteration counter is at index 0:
1 7 3 5
↑
1 is odd, so we delete it, and the situation now looks like this:
7 3 5
↑
The last thing we do in the loop iteration is to increase the iteration counter by one:
7 3 5
↑
Okay, in the next iteration, we check again: 3 is odd, so we delete it:
7 5
↑
We increase the iteration counter:
7 5
↑
And now we have the exit condition of our loop: i is no longer less than the size of the array: i is 2 and the size is also 2.
Note that in the JRuby implementation, the size is checked with a call to the size() method, which means it is re-calculated every time. In Rubinius, however, the size is cached, and only calculated once before the loop starts. Therefore, Rubinius will actually try to keep going here and access the third element of the backing tuple which doesn't exist, which leads to this NoMethodError exception:
NoMethodError: undefined method `odd?' on nil:NilClass.
Accessing a non-existing element of a Rubinius::Tuple returns nil, and each is then passing that nil to the block, which tries to call Integer#odd?.
It is important to note that Rubinius is doing nothing wrong here. The fact that it raises an exception is not a bug in Rubinius. The bug is in your code: mutating a collection while iterating over it is simply not allowed.
All of this now explains why the solution which calls Array#uniq first works: Array#uniq returns a new array, so the array you are iterating over (the one returned returned from Array#uniq) and the array you are mutating (the one referenced by the array parameter binding) are two different arrays. You would have gotten the same result with, e.g. Object#clone, Object#dup, Enumerable#map, or many others. Just as an example:
def filter_out(array)
array.map(&:itself).each { |el| array.delete(el) if yield el }
end
arr_2 = [1, 7, 3, 5]
filter_out(arr_2, &:odd?)
p arr_2
However, a more idiomatic Ruby solution would be something like this:
def filter_out(array, &blk)
array.delete_if(&blk)
end
arr_2 = [1, 7, 3, 5]
arr_3 = filter_out(arr_2, &:odd?)
p arr_3
This fixes all the problems with your code:
It doesn't mutate the array.
It doesn't mutate any argument.
In fact, there is no mutation going on at all.
It uses existing methods from the Ruby core library instead of re-inventing the wheel.
No bang !
Two spaces indentation.
The only real question is whether the method is needed at all, or if it would make more sense to just write
arr_2 = [1, 7, 3, 5]
arr_3 = arr_2.delete_if(&:odd?)
p arr_3

How does Ruby enumerator terminate iteration?

Friends, please I need help with this explanation: In the Ruby code below, what condition termites the loop do? It's supposed to be an infinite loop, but, how does it terminate?
# Ruby code
fib = Enumerator.new do |y|
a = b = 1
loop do
y << a
a, b = b, a + b
end
end
p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
Your contributions will be highly appreciated.
(Source: https://rossta.net/blog/infinite-sequences-in-ruby.html)
The way you have implemented the function fib allows it to be "lazy." What this means, is that Ruby will not try to calculate the values in fib until it absolutely has to.
The take method on the last line is key here.
p fib.take(10)
Basically, Ruby says "I'm going to evaluate the first 10 values of fib and pretend the rest do not exist, as I don't have to use them yet."
In other words, while it is true that the fib function is potentially infinite, you only asked for the first 10 values, so you only got the first 10 values.
If you tried something like this:
p fib.to_a
Your program would get stuck. Why? Because the to_a (to array) method wants to try get all the values of fib, not just a few of them. Obviously, you cannot get all the values of an infinite list.
For more information:
https://medium.com/background-thread/what-is-lazy-evaluation-programming-word-of-the-day-8a6f4410053f
https://github.com/juinc/tilap/issues/9
--- EDIT: ---
Technical correction: As Cary Swoveland pointed out, it would be more technically correct to say that fib is an algorithm/machine that produces values on demand.
An enumerator is like a Pez® dispenser, which ejects a peppermint candy each time the top of the dispenser is pressed. An enumerator version of the dispenser would not hold a supply of candies, but would manufacture the candies one at a time, on demand, possibly being capable of producing an infinite number of them.
One type of an enumerator is tied to an underlying collection of objects. Here are two that are tied to an array.
enum = [1,2,3].each #=> #<Enumerator: [1, 2, 3]:each>
enum.next #=> 1
enum.next #=> 2
enum.next #=> 3
enum.next #=> StopIteration (iteration reached an end)
enum = [1,2,3].cycle #=> #<Enumerator: [1, 2, 3]:cycle>
enum.next #=> 1
enum.next #=> 2
enum.next #=> 3
enum.next #=> 1
enum.next #=> 2
... ad infinitum
enum.first(8)
#=> [1, 2, 3, 1, 2, 3, 1, 2]
In the first example only a finite number of objects are generated by the enumerator before a StopIteration exception is raised. In the second example an arbitrary number of objects can be generated, but only on demand. first, for example, instructs enum 8 times to generate and pass to itself one object. enum is not lazy; it is all-to-eager to comply, but will not manufacture and dispense an object until it is instructed to do so.
The other type of enumerator generates objects according to a set of rules that it was born with, rules that are not tied to an underlying object. Those enumerators are generally capable of generating an infinite number of objects. The enumerator that generates Fibonacci numbers is an example of that type of enumerator. It is not a loop that does not terminate; it is a machine that is capable of producing any number of objects, but only one at a time, on demand.

Adding the number to the according index it is positioned in

def incrementer(num)
num.map.with_index(1) do |row, index|
if row > 9
row.to_s.reverse.chop.to_i
else
index + row
end
end
end
Hi,
I have a method which adds the number to the according index it is positioned in. However I have two rules:
The index starts at (1)
If the number is a multiple, remove the first integer off the end of it. 12 would become 2 for example.
The problem is I am unsure how to include an 'if' statement inside a block and I believe I am doing it wrong. I know there is a much better way to write this statement but I am finding it hard.
Example:
incrementer([4,6,9,1,3]) => [5,8,2,5,8]
- 9 + 3 (position of 9 in array) = 12
- Only its last digit 2 should be returned
Fixing your code
Use map followed by with_index(1), the argument offsetting the initial index by +1.
def incrementer(num)
num.map.with_index(1) do |row, index|
row = index + row
if row > 9
row.digits.first
else
row
end
end
end
incrementer [3, 2, 4, 10] #=> [4, 4, 7, 4]
incrementer [4, 6, 9, 1, 3] #=> [5, 8, 2, 5, 8]
Negative numbers
Numbers can be negative and for which we can use abs.digits but it may be better to use Integer#remainder.
def incrementer(num)
num.map.with_index(1) do |row, index|
row = index + row
case row
when -9..9
row
else
row.remainder 10
end
end
end
incrementer [3, 2, 4, 10]
#=> [4, 4, 7, 4]
incrementer [4, 6, 9, 1, 3]
#=> [5, 8, 2, 5,8]
incrementer [3, 2, 4,-17]
#=> [4, 4, 7, -3]
incrementer [4, 6, -22, 1, 3]
#=> [5, 8, -9, 5, 8]
Why not use % instead of Integer#remainder?
a % b returns a modulo b which is not the same thing as the remainder. This has consequences for negative numbers:
-12 % 10 #=> 8 not the last digit
So we need to use Integer#remainder, so:
-12.remainder 10 #=> -2
Which is what we need, i.e. the last digit (parity included). It can be noted in other languages such as JavaScript, a % b returns the remainder.
As noted by #moveson the above code can be refactored to:
num.map.with_index(1) { |row, index| (index + row).remainder 10 }
The #digits method requires Rails or ActiveSupport (or Ruby 2.4+), and it's not necessary. Here is a pure Ruby solution that works with any Ruby version:
def incrementer(array)
array.map.with_index(1) { |integer, index| (integer + index) % 10 }
end
This code above says: For each element of the array, add its index (starting from 1), divide the sum by 10, and return the remainder.
The % (modulo) operator divides the number before it by the number after it and returns the remainder. For example, 22 % 7 returns 1. It's an extremely useful tool and can often help avoid the use of conditionals entirely, such as in your example. Using %, you can get the last digit of a number n (whether or not n is greater than 9) by simply taking n % 10.
Now you can do:
>> incrementer([3,2,4,10])
=> [4, 4, 7, 4]
>> incrementer([4,6,9,1,3])
=> [5, 8, 2, 5, 8]
You've got two separate problems. The first problem is your use of each_with_index. Ruby functions return the value of the last expression they execute, so if you look at your function:
def incrementer(num)
num.each_with_index do |row, index|
# do some stuff
end
end
It essentially calls each_with_index and returns the value. The issue here is that each_with_index iterates over an array and then returns the original array. What you want to do is change each item in the array and return a new array with the new values. For this, you can use map:
def incrementer(num)
num.map.with_index(1) do |row, index|
# do some stuff
end
end
In this case, you can even conveniently pass in the parameter 1 to tell the iterator to start at index 1.
Now the second problem is that your if-else-statement either iterates a number or wraps it around. But what you actually want to do is iterate a number and wrap it around if it's bigger than 9. You can do that like so:
def incrementer(num)
num.map.with_index(1) do |row, index|
row = index + row
if row > 9
row.to_s.reverse.chop.to_i
else
row
end
end
end
What we're doing here is iterating the number first, saving it into row and then checking to see if it's over 9. If it is, we return the last digit; otherwise, we just return the value row.
This code will do what you want, but let's make one more change for the sake of clarity. This code:
row.to_s.reverse.chop.to_i
Is a little bit confusing. Ruby 2.4 has a convenient method for getting at the digits of an integer:
row.digits.first
This is easy to read, but it's a bit slow since it turns an integer into an array of integers. A better way is to use modulus % to get the remainder of your number, divided by 10. This is fast and easy to read for most programmers, since it's a common trick.
row % 10
Putting it all together, you get:
def incrementer(num)
num.map.with_index(1) do |row, index|
row = index + row
if row > 9
row % 10
else
row
end
end
end
Special thanks to (#sagarpandya84) and (#moveson) for allowing me to build on their answers.

Alphabetical sorting of an array without using the sort method

I have been working through Chris Pine's tutorial for Ruby and am currently working on a way to sort an array of names without using sort.
My code is below. It works perfectly but is a step further than I thought I had got!
puts "Please enter some names:"
name = gets.chomp
names = []
while name != ''
names.push name
name = gets.chomp
end
names.each_index do |first|
names.each_index do |second|
if names[first] < names[second]
names[first], names[second] = names[second], names[first]
end
end
end
puts "The names you have entered in alphabetical order are: " + names.join(', ')
It is the sorting that I am having trouble getting my head around.
My understanding of it is that each_index would look at the position of each item in the array. Then the if statement takes each item and if the number is larger than the next it swaps it in the array, continuing to do this until the biggest number is at the start. I would have thought that this would just have reversed my array, however it does sort it alphabetically.
Would someone be able to talk me through how this algorithm is working alphabetically and at what point it is looking at what the starting letters are?
Thanks in advance for your help. I'm sure it is something very straightforward but after much searching I can't quite figure it out!
I think the quick sort algorithm is one of the easier ones to understand:
def qsort arr
return [] if arr.length == 0
pivot = arr.shift
less, more = arr.partition {|e| e < pivot }
qsort(less) + [pivot] + qsort(more)
end
puts qsort(["George","Adam","Michael","Susan","Abigail"])
The idea is that you pick an element (often called the pivot), and then partition the array into elements less than the pivot and those that are greater or equal to the pivot. Then recursively sort each group and combine with the pivot.
I can see why you're puzzled -- I was too. Look at what the algorithm does at each swap. I'm using numbers instead of names to make the order clearer, but it works the same way for strings:
names = [1, 2, 3, 4]
names.each_index do |first|
names.each_index do |second|
if names[first] < names[second]
names[first], names[second] = names[second], names[first]
puts "[#{names.join(', ')}]"
end
end
end
=>
[2, 1, 3, 4]
[3, 1, 2, 4]
[4, 1, 2, 3]
[1, 4, 2, 3]
[1, 2, 4, 3]
[1, 2, 3, 4]
In this case, it started with a sorted list, then made a bunch of swaps, then put things back in order. If you only look at the first couple of swaps, you might be fooled into thinking that it was going to do a descending sort. And the comparison (swap if names[first] < names[second]) certainly seems to imply a descending sort.
The trick is that the relationship between first and second is not ordered; sometimes first is to the left, sometimes it's to the right. Which makes the whole algorithm hard to reason about.
This algorithm is, I guess, a strange implementation of a Bubble Sort, which I normally see implemented like this:
names.each_index do |first|
(first + 1...names.length).each do |second|
if names[first] > names[second]
names[first], names[second] = names[second], names[first]
puts "[#{names.join(', ')}]"
end
end
end
If you run this code on the same array of sorted numbers, it does nothing: the array is already sorted so it swaps nothing. In this version, it takes care to keep second always to the right of first and does a swap only if the value at first is greater than the value at second. So in the first pass (where first is 0), the smallest number winds up in position 0, in the next pass the next smallest number winds up in the next position, etc.
And if you run it on array that reverse sorted, you can see what it's doing:
[3, 4, 2, 1]
[2, 4, 3, 1]
[1, 4, 3, 2]
[1, 3, 4, 2]
[1, 2, 4, 3]
[1, 2, 3, 4]
Finally, here's a way to visualize what's happening in the two algorithms. First the modified version:
0 1 2 3
0 X X X
1 X X
2 X
3
The numbers along the vertical axis represent values for first. The numbers along the horizontal represent values for second. The X indicates a spot at which the algorithm compares and potentially swaps. Note that it's just the portion above the diagonal.
Here's the same visualization for the algorithm that you provided in your question:
0 1 2 3
0 X X X X
1 X X X X
2 X X X X
3 X X X X
This algorithm compares all the possible positions (pointlessly including the values along the diagonal, where first and second are equal). The important bit to notice, though, is that the swaps that happen below and to the left of the diagonal represent cases where second is to the left of first -- the backwards case. And also note that these cases happen after the forward cases.
So essentially, what this algorithm does is reverse sort the array (as you had suspected) and then afterwards forward sort it. Probably not really what was intended, but the code sure is simple.
Your understanding is just a bit off.
You said:
Then the if statement takes each item and if the number is larger than the next it swaps it in the array
But this is not what the if statement is doing.
First, the two blocks enclosing it are simply setting up iterators first and second, which each count from the first to the last element of the array each time through the block. (This is inefficient but we'll leave discussion of efficient sorting for later. Or just see Brian Adkins' answer.)
When you reach the if statement, it is not comparing the indices themselves, but the names which are at those indices.
You can see what's going on by inserting this line just before the if. Though this will make your program quite verbose:
puts "Comparing names[#{first}] which is #{names[first]} to names[#{second}] which is #{names[second]}..."
Alternatively, you can create a new array and use a while loop to append the names in alphabetical order. Delete the elements that have been appended in the loop until there are no elements left in the old array.
sorted_names = []
while names.length!=0
sorted_names << names.min
names.delete(names.min)
end
puts sorted_names
This is the recursive solution for this case
def my_sort(list, new_array = nil)
return new_array if list.size <= 0
if new_array == nil
new_array = []
end
min = list.min
new_array << min
list.delete(min)
my_sort(list, new_array)
end
puts my_sort(["George","Adam","Michael","Susan","Abigail"])
Here is my code to sort items in an array without using the sort or min method, taking into account various forms of each item (e.g. strings, integers, nil):
def sort(objects)
index = 0
sorted_objects = []
while index < objects.length
sorted_item = objects.reduce do |min, item|
min.to_s > item.to_s ? item : min
end
sorted_objects << sorted_item
objects.delete_at(objects.find_index(sorted_item))
end
index += 1
sorted_objects
end
words_2 = %w{all i can say is that my life is pretty plain}
p sort(words_2)
=> ["all", "can", "i", "is", "is", "life", "my", "plain", "pretty", "say", "that"]
mixed_array_1 = ["2", 1, "5", 4, "3"]
p sort(mixed_array_1)
=> [1, "2", "3", 4, "5"]
mixed_array_2 = ["George","Adam","Michael","Susan","Abigail", "", nil, 4, "5", 100]
p sort(mixed_array_2)
=> ["", nil, 100, 4, "5", "Abigail", "Adam", "George", "Michael", "Susan"]

Iterate every two elements in ruby for loop

How do you create a for loop like
for (int x=0; x<data.length; x+=2)
in ruby? I want to iterate through an array but have my counter increment by two instead of one.
If what you really want is to consume 2 items from an array at a time, check out each_slice.
[1,2,3,4,5,6,7,8,9].each_slice(2) do |a, b|
puts "#{a}, #{b}"
end
# result
1, 2
3, 4
5, 6
7, 8
9,
Ruby's step is your friend:
0.step(data.length, 2).to_a
=> [0, 2, 4, 6]
I'm using to_a to show what values this would return. In real life step is an enumerator, so we'd use it like:
data = [0, 1, 2, 3, 4, 5]
0.step(data.length, 2).each do |i|
puts data[i]
end
Which outputs:
0
2
4
<== a nil
Notice that data contains six elements, so data.length returns 6, but an array is a zero-offset, so the last element would be element #5. We only get three values, plus a nil which would display as an empty line when printed, which would be element #6:
data[6]
=> nil
That's why we don't usually walk arrays and container using outside iterators in Ruby; It's too easy to fall off the end. Instead, use each and similar constructs, which always do the right thing.
To continue to use step and deal with the zero-offset for arrays and containers, you could use:
0.step(data.length - 1, 2)
but I'd still try working with each and other array iterators as a first choice, which #SergioTulentsev was giving as an example.
(0..data.length).step(2) do |x|
puts x
end
This seems like the closest substitute.
Using Range#step:
a = (1..50).to_a
(1..a.size).step(2).map{|i| a[i-1]} # [1, 3, 5, 7, 9 ...

Resources