Ruby method overloading - ruby

So I have to implement two different situations. One is a method that multiplies two numbers, and can also multiply more than 2 numbers.
I'm using the following:
def multiply(arr)
arr.reduce(1, :*)
end
So far it works out fine if I unit test using an array input. Is there anyway to do this so my method can take in just two values, or an array, and return the relevant results? Is there also a way to implement this without even using an array input?

Use the splat operator:
def multiply(*arr)
arr.reduce(1, :*)
end
multiply(2, 3, 4, 5)
# => 120
If you want to also want to support input as an array, you can use flatten on arr:
def multiply(*arr)
arr.flatten.reduce(1, :*)
end
multiply([2, 3, 4, 5])
# => 120
multiply(10, 3, 5)
# => 150
multiply(10, 3)
# => 30

Related

We have 'index' and 'rindex', we have 'find' but no 'rfind'

When applied to an Array, index (invoked with a block) returns the index of the first element satisfying the condition, and rindex returns the index of the last one. Similarly, we have find to return the element itself. However, there is no corresponding rfind that would return the last element of an array satisfying a condition.
Does Ruby already have a method that accomplishes this?
Before monkey-patching the Array class, I want to make sure.
You can do it like this:
enum = [1, 2, 3, 4].reverse_each
# => #<Enumerator: [1, 2, 3, 4]:reverse_each>
enum.find(&:odd?)
# => 3
Notice that, unlike using Array#reverse, it does not create a temporal array that is thrown out immediately.
Doing it at once:
[1, 2, 3, 4].reverse_each.find(&:odd?)
# => 3
In other words, we have reverse_each.find instead of rfind; not a big deal.

What are the differences between "each", "foreach", "collect" and "map"? [duplicate]

This question already has answers here:
what's different between each and collect method in Ruby [duplicate]
(7 answers)
Closed 8 years ago.
It seems like there are a lot of ways to loop over an Enumerable in Ruby. Are there any differences between each, foreach, or in collect, map or other similar methods?
Or is there a reason I shouldn't use certain methods in certain situations?
collect/map are equivalent. They differ from each in that each only executes the block for each element, whereas collect/map return an array with the results of calling the block for each element. Another way to put it might be, each is expected to do something with each element, whereas map is expected to transform each element (map it onto something else).
You could use collect or map anywhere each is used, and your code will still work. But it will probably be slightly less efficient because it collects the results in an array, unless your Ruby implementation realizes it doesn't have to bother creating an array because it's never used.
Another reason to use each instead of map or collect is to help out anyone reading your code. If I see each then I can be like okay, we're about to use each element of the data to do something. If I see map then I'm expecting to see new data being created, based on a remapping of the old data.
With regards to map vs. collect I would say it's a matter of preference, but you should pick one and stick with it for consistency.
Using pry and Rubinus (it's easier to read ruby code) take a look for yourself
$ pry
[1] pry(main)> cd Enumerable
[2] pry(Enumerable):1> show-method collect
From: .../rbx-head/kernel/common/enumerable18.rb # line 4:
Owner: Enumerable
Visibility: public
Number of lines: 9
def collect
if block_given?
ary = []
each { |o| ary << yield(o) }
ary
else
to_a
end
end
[3] pry(Enumerable):1> show-method map
From: .../rbx-head/kernel/common/enumerable18.rb # line 4:
Owner: Enumerable
Visibility: public
Number of lines: 9
def collect
if block_given?
ary = []
each { |o| ary << yield(o) }
ary
else
to_a
end
end
[4] pry(Enumerable):1>
So nope not for these two.
map and collect iterate over a collection. For each object it executes your block then collects the result. The each methods do not collect the results
Array#collect (and Array#map) return a new array based on the code passed in the block. Array#each performs an operation (defined by the block) on each element of the array.
I would use collect like this:
array = [1, 2, 3]
array2 = array.collect {|val| val + 1}
array.inspect # => "[1, 2, 3]"
array2.inspect # => "[2, 3, 4]"
And each like this:
array = [1, 2, 3]
array.each {|val| puts val + 1 }
# >> 2
# >> 3
# >> 4
array.inspect # => "[1, 2, 3]"

Can i check if an array e.g. just holds integers in ruby?

Title, i think is self declaring. I am kind of a java-developer and wanna ensure that my array holds just integer values. I know everything in ruby is a object. I find it inconvenient to loop through the array and make checks at every element. Is there any shortcut to this in ruby?
Use Enumerable#all? with a block. Integer numbers are instances of class Integer in ruby.
[1, 2, 3].all? {|i| i.is_a?(Integer) } # => true
[1, 2, 3, '4'].all? {|i| i.is_a?(Integer) } # => false

How to act differently on the first iteration in a Ruby loop?

I always use a counter to check for the first item (i==0) in a loop:
i = 0
my_array.each do |item|
if i==0
# do something with the first item
end
# common stuff
i += 1
end
Is there a more elegant way to do this (perhaps a method)?
You can do this:
my_array.each_with_index do |item, index|
if index == 0
# do something with the first item
end
# common stuff
end
Try it on ideone.
Using each_with_index, as others have described, would work fine, but for the sake of variety here is another approach.
If you want to do something specific for the first element only and something general for all elements including the first, you could do:
# do something with my_array[0] or my_array.first
my_array.each do |e|
# do the same general thing to all elements
end
But if you want to not do the general thing with the first element you could do:
# do something with my_array[0] or my_array.first
my_array.drop(1).each do |e|
# do the same general thing to all elements except the first
end
Arrays have an "each_with_index" method which is handy for this situation:
my_array.each_with_index do |item, i|
item.do_something if i==0
#common stuff
end
What fits best is depending on the situation.
Another option (if you know your array is not empty):
# treat the first element (my_array.first)
my_array.each do | item |
# do the common_stuff
end
each_with_index from Enumerable (Enumerable is already mixed in with Array, so you can call it on an array without any trouble):
irb(main):001:0> nums = (1..10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
irb(main):003:0> nums.each_with_index do |num, idx|
irb(main):004:1* if idx == 0
irb(main):005:2> puts "At index #{idx}, the number is #{num}."
irb(main):006:2> end
irb(main):007:1> end
At index 0, the number is 1.
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
If you don't need the array afterwards:
ar = %w(reversed hello world)
puts ar.shift.upcase
ar.each{|item| puts item.reverse}
#=>REVERSED
#=>olleh
#=>dlrow
Ruby's Enumerable#inject provides an argument that can be used for doing something differently on the first iteration of a loop:
> l=[1,2,3,4]
=> [1, 2, 3, 4]
> l.inject(0) {|sum, elem| sum+elem}
=> 10
The argument is not strictly necessary for common things like sums and products:
> l.inject {|sum, elem| sum+elem}
=> 10
But when you want to do something different on the first iteration, that argument might be useful to you:
> puts fruits.inject("I like to eat: ") {|acc, elem| acc << elem << " "}
I like to eat: apples pears peaches plums oranges
=> nil
Here's a solution that doesn't need to be in an immediately enclosing loop and avoids the redundancy of specifying a status placeholder more than once unless you really need to.
do_this if ($first_time_only ||= [true]).shift
Its scope matches the holder: $first_time_only will be globally once; #first_time_only will be once for the instance, and first_time_only will be once for the current scope.
If you want the first several times, etc, you can easily put [1,2,3] if you need to distinguish which of the first iterations you're in, or even something fancy [1, false, 3, 4] if you need something weird.

What does the syntax [*a..b] mean in Ruby?

NOTE: mischa's splat on GitHub has lots of cool interactive examples of * in action.
By googling, I found that one way to iterate over a range of numbers in Ruby (your classic C-style for loop)
for (i = first; i <= last; i++) {
whatever(i);
}
is to do something like this
[*first..last].each do |i|
whatever i
end
But what exactly is going on with that [*first..last] syntax? I played around with irb and I see this:
ruby-1.9.2-p180 :001 > 0..5
=> 0..5
ruby-1.9.2-p180 :002 > [0..5]
=> [0..5]
ruby-1.9.2-p180 :003 > [*0..5]
=> [0, 1, 2, 3, 4, 5]
ruby-1.9.2-p180 :004 > *0..5
SyntaxError: (irb):4: syntax error, unexpected tDOT2, expecting tCOLON2 or '[' or '.'
*0..5
^
Everything I've read online discusses the unary asterisk as being useful for expanding and collapsing arguments passed to a method, useful for variable length argument lists
def foo(*bar)
bar
end
foo 'tater' # => ["tater"]
foo 'tater', 'tot' # => ["tater", "tot"]
and I get that, but I don't see how it applies to the expansion being done in my block example above.
To be clear, I know that The Ruby Way is to iterate over an array or collection, not to use the array length and iterate with an integer index. However, in this example, I really am dealing with a list of integers. :)
[*1..10]
is the same thing as
(1..10).to_a # call the "to array" method
Instances of the Array class you have created implement Enumerable so your loop works. On classes that define a to_a method, you can use the splat operator syntax with brackets. Splat does a lot more than just call #to_a though, and would be worth a Google search on its own.
Now, in your case, the Range class itself is already an Enumerable so you could just do:
(first..last).each do |v|
...
end
[first..last] is an array containing only 1 range object. [*first..last] is an array containing the elements of that range having been sent in as an argument list. * works in the context of an argument list.
It is called a splat operator. If you use it within certain positions like an argument position or an array, it will expand into its elements:
a = [1]
[*a, 3] # => [1, 3]
b = [1, 2]
[*b, 3] # => [1, 2, 3]
You can't use it bare or in ranges:
*a..3 # => error.
(*a..3) # => error.
When you have something that is not an array, it returns itself:
a = 1
[*a, 3] # => [1, 3]

Resources