I'm writing a program that pushes Fibonacci numbers into an array, using Ruby. The code works, but I can't wrap my head around why it works.
This part I understand, it's the Fibonacci equation:
fib_array = []
def fib (n)
return n if n <= 1
fib(n - 1) + fib(n - 2)
end
This is what I don't understand:
10.times do |x|
fib_array << fib(x)
end
print fib_array
I wrote this grasping at straws, and it works. I don't understand why. I didn't feed it a number to start at, does Ruby take that to mean 0? Also, how did it know to compound the numbers instead of printing [0, 0, 0...]? I apologize if this is a dunderheaded question, but I'm at loss.
It looks like the bottom piece of code simply calls the fib function on x=0, x=1 ... x=9 and stores it's return value at the end of the array. When times is invoked with an iteration variable (x), it begins at 0 and increments on each iteration through the loop. You never fed it a value, however it manages to successfully solve the problem with the iteration variable x being passed in as the parameter to fib.
The second part of your code says:
"From the instance 10 of the class Integer, call the method times with the given block" (The method "recive" a block implicitly).
What is a block? A small piece of code between {braces} or a do-end (like you did).
The method times is called, "iterator". And it will yield 0,1,2,..,9 (in your case). An iterator and the yield statement are always together. Think that yield is like return with memory, when you look for more information.
So, your code could be re-writing like:
10.times { |x| fib_array << fib(x) }
And it will call, the block you pass, on every yield that the method times
does. Calling the method << (append) to the result of fib(x) on your array.
We have:
def fib (n)
return n if n <= 1
fib(n - 1) + fib(n - 2)
end
which you understand. First let's see what are the first 5 Fibonacci numbers::
fib_array = []
5.times do |x|
fib_array << fib(x)
end
fib_array
#=> [0, 1, 1, 2, 3]
Now let's break this down and see what happening. First look at the docs for the method times. To find them, we need to know what class or module the method is from, because that's how the docs are organized. As 5.class #=> Fixnum, we might look at the docs for Fixnum. Hmmm. times is not there. Evidentally, it was inherited from another class. Let's check:
Fixnum.ancestors
#=> [Fixnum, Integer, Numeric, Comparable, Object, Kernel, BasicObject]
Integer includes Fixnum and BigNum, Numeric includes Integer and Float. (3.14).times doesn't make sense, so it appears times is defined in Integer, and so it is: Integer#times. By defining it there, it is inherited by both Fixnum and Bignum.
Here's a direct way to determine where the method came from:
5.method(:times).owner #=> Integer
It's not important understand this now, but you'll find it handy as you gain experience with Ruby.
OK, the docs say that times return a value if given a block, or an enumerator if not. Let's forget about the block a moment and look at the enumerator that is returned:
enum = 5.times #=> #<Enumerator: 5:times>
The method Enumerator#each passes the elements of the enumerator enum to its block:
do |x|
fib_array << fib(x)
end
assigning them to the block variable x. To see the contents of the enumerator, convert it to an array:
enum.to_a #=> [0, 1, 2, 3, 4]
The result is:
fib_array = []
enum.each do |x|
fib_array << fib(x)
end
fib_array
#=> [0, 1, 1, 2, 3]
which of course is the same result that we obtained previously. Now let's see what's happening step-by-by, by using the method Enumerator#next to extract each element of the enumerator:
x = enum.next #=> 0
fib(x) #=> 0
fib_array << fib(x) #=> [0]
x = enum.next #=> 1
fib(x) #=> 1
fib_array << fib(x) #=> [0, 1]
x = enum.next #=> 2
fib(x) #=> 1
fib_array << fib(x) #=> [0, 1, 1]
x = enum.next #=> 3
fib(x) #=> 2
fib_array << fib(x) #=> [0, 1, 1, 2]
x = enum.next #=> 4
fib(x) #=> 3
fib_array << fib(x) #=> [0, 1, 1, 2, 3]
print fib_array # [0, 1, 1, 2, 3]
That's all there is to it.
Related
I am asked to write some code in Ruby that iterates over every n-th element of an array and prints it until all elements of the array are printed.
The question reads:
Imagine an iterator that accesses an array in strides and runs some code at each stride. If the strides reach the end of the array then they simply begin anew from the array's beginning.
For example:
x = [0,1,2,3,4]
x.stride(1) do |elem|; puts elem; end # prints 0,1,2,3,4
x.stride(2) do |elem|; puts elem; end # prints 0,2,4,1,3
x.stride(8) do |elem|; puts elem; end # prints 0,3,1,4,2
[].stride(2) do |elem|; puts elem; end # does not print anything, but the code is correct
Assume that the stride is equal or greater than 1, and that both the stride and the array's size are not a integral/whole multiple of each other, meaning that the whole array can be printed using a given stride. Fill in the code that's missing:
class Array
def stride(step)
numelems = ... # size of the array
...
end
end
It is obvious that numelemns = self.length(). However am having trouble with the rest.
I am going to try writing some code in Python that accomplishes this task, but I am afraid that I will not be able to translate it to Ruby.
Any ideas? The answer should not be more than 4-5 lines long as the question is one that our proffessor gave us to solve in a couple of minutes.
A solution to this is provided below (thanks #user3574603):
class Array
def stride(step)
yield self[0]
(self * step).map.with_index do |element, index|
next element if index == 0
yield element if index % step == 0
end
end
end
The following assumes that arr.size and n are not both even numbers and arr.size is not a multiple of n.
def striding(arr, n)
sz = arr.size
result = '_' * sz
idx = 0
sz.times do
result[idx] = arr[idx].to_s
puts "S".rjust(idx+1)
puts result
idx = (idx + n) % sz
end
end
striding [1,2,3,4,5,6,7,8,9,1,2,3,4,5,6], 7
S
1______________
S
1______8_______
S
1______8______6
S
1_____78______6
S
1_____78_____56
S
1____678_____56
S
1____678____456
S
1___5678____456
S
1___5678___3456
S
1__45678___3456
S
1__45678__23456
S
1_345678__23456
S
1_345678_123456
S
12345678_123456
S
123456789123456
Here is an example where arr.size is a multiple of n.
striding [1,2,3,4,5,6], 3
S
1_____
S
1__4__
S
1__4__
S
1__4__
S
1__4__
S
1__4__
Here is an example where arr.size and n are both even numbers.
striding [1,2,3,4,5,6,7,8], 6
S
1_______
S
1_____7_
S
1___5_7_
S
1_3_5_7_
S
1_3_5_7_
S
1_3_5_7_
S
1_3_5_7_
S
1_3_5_7_
Imagine an iterator that accesses an array in strides and runs some code at each stride. If the strides reach the end of the array then they simply begin anew from the array's beginning.
Based on this specification, stride will always iterate forever, unless the array is empty. But that is not a problem, since we can easily take only the amount of elements we need.
In fact, that is a good design: producing an infinite stream of values lets the consumer decide how many they need.
A simple solution could look like this:
module CoreExtensions
module EnumerableExtensions
module EnumerableWithStride
def stride(step = 1)
return enum_for(__callee__, step) unless block_given?
enum = cycle
loop do
yield(enum.next)
(step - 1).times { enum.next }
end
self
end
end
end
end
Enumerable.include(CoreExtensions::EnumerableExtensions::EnumerableWithStride)
A couple of things to note here:
I chose to add the stride method to Enumerable instead of Array. Enumerable is Ruby's work horse for iteration and there is nothing in the stride method that requires self to be an Array. Enumerable is simply the better place for it.
Instead of directly monkey-patching Enumerable, I put the method in a separate module. That makes it easier to debug code for others. If they see a stride method they don't recognize, and inspect the inheritance chain of the object, they will immediately see a module named EnumerableWithStride in the inheritance chain and can make the reasonable assumption that the method is probably coming from here:
[].stride
# Huh, what is this `stride` method? I have never seen it before.
# And it is not documented on https://ruby-doc.org/
# Let's investigate:
[].class.ancestors
#=> [
# Array,
# Enumerable,
# CoreExtensions::EnumerableExtensions::EnumerableWithStride,
# Object,
# Kernel,
# BasicObject
# ]
# So, we're confused about a method named `stride` and we
# found a module whose name includes `Stride`.
# We can reasonably guess that somewhere in the system,
# there must be a file named
# `core_extensions/enumerable_extensions/enumerable_with_stride.rb`.
# Or, we could ask the method directly:
meth = [].method(:stride)
meth.owner
#=> CoreExtensions::EnumerableExtensions::EnumerableWithStride
meth.source_location
#=> [
# 'core_extensions/enumerable_extensions/enumerable_with_stride.rb',
# 6
# ]
For an empty array, nothing happens:
[].stride(2, &method(:p))
#=> []
stride just returns self (just like each does) and the block is never executed.
For a non-empty array, we get an infinite stream of values:
x.stride(&method(:p))
# 0
# 1
# 2
# 3
# 4
# 0
# 1
# …
x.stride(2, &method(:p))
# 0
# 2
# 4
# 1
# 3
# 0
# 2
# …
x.stride(8, &method(:p))
# 0
# 3
# 1
# 4
# 2
# 0
# 3
# …
The nice thing about this infinite stream of values is that we, as the consumer can freely choose how many elements we want. For example, if I want 10 elements, I simply take 10 elements:
x.stride(3).take(10)
#=> [0, 3, 1, 4, 2, 0, 3, 1, 4, 2]
This works because, like all well-behaved iterators, our stride method returns an Enumerator in case no block is supplied:
enum = x.stride(2)
#=> #<Enumerator: ...>
enum.next
#=> 0
enum.next
#=> 2
enum.next
#=> 4
enum.next
#=> 1
enum.next
#=> 3
enum.next
#=> 0
enum.next
#=> 2
So, if we want to implement the requirement "until all the elements of the array are printed":
I am asked to write some code in Ruby that iterates over every n-th element of an array and prints it until all elements of the array are printed.
We could implement that something like this:
x.stride.take(x.length).each(&method(:p))
x.stride(2).take(x.length).each(&method(:p))
x.stride(8).take(x.length).each(&method(:p))
This is a pretty simplistic implementation, though. Here, we simply print as many elements as there are elements in the original array.
We could implement a more sophisticated logic using Enumerable#take_while that keeps track of which elements have been printed and which haven't, and only stops if all elements are printed. But we can easily prove that after x.length iterations either all elements have been printed or there will never be all elements printed (if the stride size is an integral multiple of the array length or vice versa). So, this should be fine.
This almost does what I think you want but breaks if the step is array.length + 1 array.length (but you mention that we should assume the stride is not a multiply of the array length).
class Array
def exhaustive_stride(step)
(self * step).map.with_index do |element, index|
next element if index == 0
element if index % step == 0
end.compact
end
end
x.exhaustive_stride 1
#=> [0, 1, 2, 3, 4]
x.exhaustive_stride 2
#=> [0, 2, 4, 1, 3]
x.exhaustive_stride 8
#=> [0, 3, 1, 4, 2]
[].exhaustive_stride 2
#=> []
Using the example array, it breaks when the stride is 5.
[0,1,2,3,4].exhaustive_stride 5
#=> [0, 0, 0, 0, 0]
Note
This works but the intermediate array makes it highly inefficient. Consider other answers.
Here's another solution that uses recursion. Not the most efficient but one way of doing it.
class Array
def exhaustive_stride(x, r = [])
return [] if self.empty?
r << self[0] if r.empty?
while x > self.length
x -= self.length
end
r << self[x]
x += x
return r if r.count == self.count
stride(x, r)
end
end
[0,1,2,3,4].exhaustive_stride 1
#=> [0, 1, 2, 4, 3]
[0,1,2,3,4].exhaustive_stride 2
#=> [0, 2, 4, 3, 1]
[0,1,2,3,4].exhaustive_stride 8
#=> [0, 3, 1, 2, 4]
[].exhaustive_stride 2
#=> []
[0,1,2,3,4].exhaustive_stride 100_000_001
#=> [0, 1, 2, 4, 3]
This would work:
def stride(ary, step)
raise ArgumentError unless step.gcd(ary.size) == 1
Array.new(ary.size) { |i| ary[(i * step) % ary.size] }
end
Example:
x = [0, 1, 2, 3, 4]
stride(x, 1) #=> [0, 1, 2, 3, 4]
stride(x, 2) #=> [0, 2, 4, 1, 3]
stride(x, 8) #=> [0, 3, 1, 4, 2]
stride(x, -1) #=> [0, 4, 3, 2, 1]
First of all, the guard clause checks whether step and ary.size are coprime to ensure that all elements can be visited via step.
Array.new(ary.size) creates a new array of the same size as the original array. The elements are then retrieved from the original array by multiplying the element's index by step and then performing a modulo operation using the array's size.
Having % arr.size is equivalent to fetching the elements from a cyclic array, e.g. for a step value of 2:
0 1 2 3 4
| | | | |
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4, ...
To turn this into an instance method for Array you merely replace ary with self (which can be omitted most of the time):
class Array
def stride(step)
raise ArgumentError unless step.gcd(size) == 1
Array.new(size) { |i| self[(i * step) % size] }
end
end
I'm working on a lab Using a generalized map method to pass an element and block through returning multiple outcomes.
Really struggled on this one. Found some responses but they don't really make sense to me.
Here is the code:
def map(s)
new = []
i = 0
while i < s.length
new.push(yield(s[i]))
i += 1
end
new
end
Here's is the test:
it "returns an array with all values made negative" do
expect(map([1, 2, 3, -9]){|n| n * -1}).to eq([-1, -2, -3, 9])
end
it "returns an array with the original values" do
dune = ["paul", "gurney", "vladimir", "jessica", "chani"]
expect(map(dune){|n| n}).to eq(dune)
end
it "returns an array with the original values multiplied by 2" do
expect(map([1, 2, 3, -9]){|n| n * 2}).to eq([2, 4, 6, -18])
end
it "returns an array with the original values squared" do
expect(map([1, 2, 3, -9]){|n| n * n}).to eq([1, 4, 9, 81])
end
end
I don't get how the above code can give you these 4 different results.
Could someone help me understand it ?
Thank you for your help!
How your method map works
To see how your method operates let's modify your code to add some intermediate variables and some puts statements to show the values of those variables.
def map(s)
new = []
i = 0
n = s.length
puts "s has length #{n}"
while i < n
puts "i = #{i}"
e = s[i]
puts " Yield #{e} to the block"
rv = yield(e)
puts " The block's return value is #{rv}. Push #{rv} onto new"
new.push(rv)
puts " new now equals #{new}"
i += 1
end
puts "We now return the value of new"
new
end
Now let's execute the method with one of the blocks of interest.
s = [1, 2, 3, -9]
map(s) { |n| n * 2 }
#=> [2, 4, 6, -18] (return value of method)
The following is displayed.
s has length 4
i = 0
Yield 1 to the block
The block's return value is 2. Push 2 onto new
new now equals [2]
i = 1
Yield 2 to the block
The block's return value is 4. Push 4 onto new
new now equals [2, 4]
i = 2
Yield 3 to the block
The block's return value is 6. Push 6 onto new
new now equals [2, 4, 6]
i = 3
Yield -9 to the block
The block's return value is -18. Push -18 onto new
new now equals [2, 4, 6, -18]
We now return the value of new
It may by of interest to execute this modified method with different values of s and different blocks.
A replacement for Array#map?
Is this a replacement for Array#map (or Enumerable#map, but for now let's just consider Array#map)? As you defined it at the top level your map is an instance method of the class Object:
Object.instance_methods.include?(:map) #=> true
It must be invoked map([1,2,3]) { |n| ... } whereas Array#map is invoked [1,2,3].map { |n| ... }. Therefore, for your method map to be a replacement for Array#map you need to define it as follows.
class Array
def map
new = []
i = 0
while i < length
new.push(yield(self[i]))
i += 1
end
new
end
end
[1, 2, 3, -9].map { |n| n * 2 }
#=> [2, 4, 6, -18]
Simplify
We can simplify this method as follows.
class Array
def map
new = []
each { |e| new << yield(e) }
new
end
end
[1, 2, 3, -9].map { |n| n * 2 }
#=> [2, 4, 6, -18]
or, better:
class Array
def map
each_with_object([]) { |e,new| new << yield(e) }
end
end
See Enumerable#each_with_object.
Note that while i < length is equivalent to while i < self.length, because self., if omitted, is implicit, and therefore redundant. Similarly, each { |e| new << yield(e) } is equivalent to self.each { |e| new << yield(e) } and each_with_object([]) { ... } is equivalent to self.each_with_object([]) { ... }.
Are we finished?
If we examine the doc Array#map carefully we see that there are two forms of the method. The first is when map takes a block. Our method Array#map mimics that behaviour and that is the only behaviour needed to satisfy the given rspec tests.
There is a second form, however, where map is not given a block, in which case it returns an enumerator. That allows us to chain the method to another. For example (with Ruby's Array#map),
['cat', 'dog', 'pig'].map.with_index do |animal, i|
i.even? ? animal.upcase : animal
end
#=> ["CAT", "dog", "PIG"]
We could modify our Array#map to incorporate this second behaviour as follows.
class Array
def map
if block_given?
each_with_object([]) { |e,new| new << yield(e) }
else
to_enum(:map)
end
end
end
[1, 2, 3, -9].map { |n| n * 2 }
#=> [2, 4, 6, -18]
['cat', 'dog', 'pig'].map.with_index do |animal, i|
i.even? ? animal.upcase : animal
end
#=> ["CAT", "dog", "PIG"]
See Kernel#block_given? and Object#to_enum.
Notes
You might use, say, arr, rather than s as the variable holding the array, as s often denotes a string, just as h typically denotes a hash. One generally avoids names for variables and custom methods that are the names of core Ruby methods. That is also an objection to your use of new as a variable name, as there are many core methods named new.
I am currently learning Ruby and am lost a bit.
This Python snippet:
n = iter([1,2,3,4,5])
for x in n:
print(x)
y = next(n)
print(y)
gives:
1
2
3
4
5
And I'm trying to do the same in Ruby, which is not working:
n = [1,2,3,4,5].each
for x in n do
puts x
y = n.next()
puts y
end
How do I need to write the Python example in Ruby?
You have the right idea except Ruby keeps track of the position of the enumerator internally. Try this:
enum = [1,2,3,4,5].each
#=> #<Enumerator: [1, 2, 3, 4, 5]:each>
loop do
puts enum.next
puts enum.next
end
1
2
3
4
5
Enumerator#next raises a StopInteration exception when invoked after all elements of the enumerator enum have been generated. Kernel#loop handles the exception by breaking out of the loop.
Note that Array#each, without the optional block, has the same effect as Object#to_enum. Also, though authors of Ruby books feel an obligation to cover for loops (seemingly, on page one), they are never used in practice.
In Python the iterator n obtained applying the function iter() can be consumed once.
array = [1,2,3,4,5]
n = iter(array)
for x in n:
print(x)
# 1
# 2
# 3
# 4
# 5
If you then call next(n) you get no output but error: StopIteration. If you try to iterate n again you get no output (no error, the for loop hanldes the exception).
But you can iterate over the array:
for x in array:
print(x)
If you check the output a code like yours, you get:
n = iter([1,2,3,4,5])
for x in n:
print('odd_', x)
y = next(n)
print('even', y)
# odd_ 1
# even 2
# odd_ 3
# even 4
# odd_ 5
# StopIteration
As pointed by #toniedzwiedz Object#to_enum is the equivalent for the Python iter(), so you can call Enumerator#next on it.
In Ruby you can consume more than once the enumerator:
array = [1, 2, 3, 4, 5]
n = array.to_enum
# n = array.each # each returns an Enumerable
for x in n do
puts x
end
for x in n do
puts x
end
Since you can consume more than once the enumerator you get "double" output:
for x in n do
p x
p n.next
end
Or using Array#each:
n.each do |x| # same as array.each.each
p x
p n.next
end
Also in Ruby you reach end the iteration signal:
6.times do
p n.next
end
# `next': iteration reached an end (StopIteration)
You're just trying to print each element of the Array?
[1,2,3,4,5].each {|n| puts n}
If you're looking for a direct equivalent of Python's iterator, you should check out Enumerator#next for a very similar API
arr = [1, 2, 3].to_enum
#<Enumerator: [1, 2, 3]:each>
arr.next
# 1
for x in arr do
puts x
puts arr.next
end
#1
#2
#2
#3
#3
#StopIteration: iteration reached an end
each_cons is what you need. But this method has a downside that is the current will not print last element of the array. Please keep in mind this.
[1,2,3,4,5].each_cons(2) { |current,next_val| puts next_val }
I have an array a = [1, 2, 3, 4, 5]
If I have an element in the array, I can find the next element in the array via the
a[0].next
Is there a method that I can use to find the previous element
a[1].previous or a[1].before such that the result is
#=> 1
I Googled around a bit and it seems as if most other similar questions involve a loop which I don't want to do. I also checked out the Ruby docs of Enumerator & Enumerable and couldn't seem to find one.
>> a = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5]
>> a[0].next #=> 2
>> a[2].previous
NoMethodError: undefined method `previous' for 3:Fixnum
from (irb):14
from /Users/Lois/.rvm/rubies/ruby-2.3.1/bin/irb:11:in `<main>'
>> a[2].before
NoMethodError: undefined method `before' for 3:Fixnum
from (irb):15
from /Users/Lois/.rvm/rubies/ruby-2.3.1/bin/irb:11:in `<main>'
Thanks in advance!
If you have an array:
a = [ 1, 2, 3, 4 ]
Then calling a[1] will return the object 2, and there's nothing special about that value, it's without context once you've retrieved it. As such, calling next on it will always yield 3 because that's what Integer#next does.
In order to navigate through that array you need an iterator of some sort, like Enumerator:
e = a.each
Now you can do what you want:
e.next
# => 1
e.next
# => 2
Note that this interface isn't as flexible as you're expecting. You can call next to advance, or rewind to go back to the beginning, but there's no previous. Ruby doesn't have what other languages term as bi-directional iterators, but you might be able to extend this class to add the functions you need if you're feeling brave.
I always end up whipping up something like this.
This approach, of course, isn't limited to Arrays - I didn't want to make it an EnumerableScanner, however, as some enumerations maintain complex state (think of a fibonacci sequence).
class ArrayScanner
attr_reader :index, :array
def initialize(array)
#array = array
#index = 0
end
def next
raise StopIteration unless next?
#array[#index += 1]
end
def peek
raise StopIteration unless next?
#array[#index + 1]
end
def next?
#index + 1 != #array.size
end
def prev
raise StopIteration unless prev?
#array[#index -= 1]
end
def peek_prev
raise StopIteration unless prev?
#array[#index - 1]
end
def prev?
#index - 1 >= 0
end
def eof?
!next?
end
def bof?
!prev?
end
def current
#array[#index]
end
def current=(new_value)
#array[#index] = new_value
end
def size
#array.size
end
def pos
#index
end
def rewind
#index = 0
end
end
a = ArrayScanner.new [1, 2, 3, 4, 5]
a.current #=> 1
a.next #=> 2
a.current #=> 2
a.prev #=> 1
a.prev? #=> false
a.bof? #=> true
4.times { a.next }
a.eof? #=> true
a.current #=> 5
The crystal language has a similar approach, with it's Iterator module.
a = [1, 2, 3, 4, 5]
i = 0
a[i] #=> 1
a[i.next] #=> 2
a[i.pred] #=> 5
i = 1
s = 1
a[i] #=> 2
a[i + s] #=> 3
a[i - s] #=> 1
(1..4).collect do |x|
next if x == 3
x + 1
end # => [2, 3, nil, 5]
# desired => [2, 3, 5]
If the condition for next is met, collect puts nil in the array, whereas what I'm trying to do is put no element in the returned array if the condition is met. Is this possible without calling delete_if { |x| x == nil } on the returned array?
My code excerpt is heavily abstracted, so looking for a general solution to the problem.
There is method Enumerable#reject which serves just the purpose:
(1..4).reject{|x| x == 3}.collect{|x| x + 1}
The practice of directly using an output of one method as an input of another is called method chaining and is very common in Ruby.
BTW, map (or collect) is used for direct mapping of input enumerable to the output one. If you need to output different number of elements, chances are that you need another method of Enumerable.
Edit: If you are bothered by the fact that some of the elements are iterated twice, you can use less elegant solution based on inject (or its similar method named each_with_object):
(1..4).each_with_object([]){|x,a| a << x + 1 unless x == 3}
I would simply call .compact on the resultant array, which removes any instances of nil in an array. If you'd like it to modify the existing array (no reason not to), use .compact!:
(1..4).collect do |x|
next if x == 3
x
end.compact!
In Ruby 2.7+, it’s possible to use filter_map for this exact purpose. From the docs:
Returns an array containing truthy elements returned by the block.
(0..9).filter_map {|i| i * 2 if i.even? } #=> [0, 4, 8, 12, 16]
{foo: 0, bar: 1, baz: 2}.filter_map {|key, value| key if value.even? } #=> [:foo, :baz]
For the example in the question: (1..4).filter_map { |x| x + 1 unless x == 3 }.
See this post for comparison with alternative methods, including benchmarks.
just a suggestion, why don't you do it this way:
result = []
(1..4).each do |x|
next if x == 3
result << x
end
result # => [1, 2, 4]
in that way you saved another iteration to remove nil elements from the array. hope it helps =)
i would suggest to use:
(1..4).to_a.delete_if {|x| x == 3}
instead of the collect + next statement.
You could pull the decision-making into a helper method, and use it via Enumerable#reduce:
def potentially_keep(list, i)
if i === 3
list
else
list.push i
end
end
# => :potentially_keep
(1..4).reduce([]) { |memo, i| potentially_keep(memo, i) }
# => [1, 2, 4]