Reputation: 30232
Let's assume method a can return either an array or a single element
def a(n)
if n == 0
return '0'
else
return '1', '2'
end
end
irb(main):008:0> a(0)
=> "0"
irb(main):009:0> a(1)
=> ["1", "2"]
What would be the best "ruby" way to express the following:
irb(main):013:0> a(0).<???>.to_i
=> 0
irb(main):014:0> a(1).<???>.to_i
=> 1
I'm looking for an elegant syntax to achieve the above. I obviously can implement a function what would do dynamic type inspection and would either return the first element of just the input variable as is..
Upvotes: 0
Views: 104
Reputation: 114238
You could use array decomposition to assign only the first value to a variable:
x, = a(0) #=> "0"
x #=> "0"
x, = a(1) #=> ["1", "2"]
x #=> "1"
x, = ...
is equivalent to x, * = ...
or (x, *) = ...
Or as a helper method with array decomposition (other link, extra parentheses are required here):
def first((x, *))
x
end
first a(0) #=> "0"
first a(1) #=> "1"
A different approach is to yield
the values:
def a(n)
if n == 0
yield '0'
else
yield '1', '2'
end
end
a(0) { |x| x } #=> "0"
a(1) { |x| x } #=> "1"
a(0) { |*args| args } #=> ["0"]
a(1) { |*args| args } #=> ["1", "2"]
This also works nicely with Enumerator
:
def a(n)
return enum_for(:a, n) unless block_given?
if n == 0
yield '0'
else
yield '1', '2'
end
end
a(0).next #=> "0"
a(1).next #=> ["1", "2"]
a(0).next_values #=> ["0"]
a(1).next_values #=> ["1", "2"]
Upvotes: 2
Reputation: 110735
def a(n)
n.zero? ? '0' : '10', '20'
end
[*a(0)].first #=> "0"
[*a(7)].first #=> "10"
Upvotes: 1
Reputation: 29588
While I agree with all the comments that this is not a great idea.
Technically a(n)[0].to_i
works in both cases
a(0)[0].to_i
#=> 0
a(1)[0].to_i
#=> 1
String#[]
returns the nth character in the same fashion that Array#[]
returns the nth element.
Based on your example even if the first return was a Fixnum
rather than a String
. Fixnum#[]
would still work :) but only because 0[0]
returns the bit reference which just so happens to be 0
This is what duck typing is all about but it has its caveats such as if a(0)
was to return 2
instead of '0'
then you would get 0
e.g. 2[0].to_i #=> 0
because the binary representation is 10
and you are asking for the least significant bit. (first position from the right).
Since you have full control of what a
actually is it makes more sense to maintain consistency in the return value from a
. It also makes documenting the method far simpler.
def a(n)
n == 0 ? ['0'] : ['1','2']
end
Upvotes: 1
Reputation: 768
You could cast it into an array using Array()
:
Array(a(n)).first
> Array(["1","2"]).first
=> "1"
> Array("0").first
=> "0"
A better solution (if you controlled a(n)
) would be to return a consistent type from your method.
Upvotes: 4