Ternary Operator and Arrays

F

Felix Dominguez

Given:
ary = Array.new
some_hash = {'a' => 1, 'b' => 2, 'c' => 3}
another_array = ['a', 'c']

Then:
another_array.each do |x|
ary << some_hash.has_key?(key) ? ' ' : some_hash[key]
end

Expected:
ary should be [1, ' ', 3]

Actual:
[true, false, true]

Question:
Why does that happen?

-Felix
 
M

Marnen Laibow-Koser

Felix said:
Given:
ary = Array.new
some_hash = {'a' => 1, 'b' => 2, 'c' => 3}
another_array = ['a', 'c']

Then:
another_array.each do |x|
ary << some_hash.has_key?(key) ? ' ' : some_hash[key]
end

Expected:
ary should be [1, ' ', 3]

Actual:
[true, false, true]

Question:
Why does that happen?

-Felix

It's probably a precedence issue. Looks like << is binding tighter than
?: .

Anyway, you can just do ary = another_array.collect{|x| some_hash[x] ||
' '}


Best,
 
J

Jesús Gabriel y Galán

Given:
ary =3D Array.new
some_hash =3D {'a' =3D> 1, 'b' =3D> 2, 'c' =3D> 3}
another_array =3D ['a', 'c']

Then:
another_array.each do |x|
=A0 ary << =A0some_hash.has_key?(key) ? ' ' : some_hash[key]
end

Expected:
ary should be [1, ' ', 3]

Actual:
[true, false, true]

Question:
Why does that happen?

First of all, I assume you copy/pasted wrong, since I get

NameError: undefined local variable or method `key' for main:Object

Assuming you want to query the hash for each value of the
another_array, you can do this:

irb(main):025:0> another_array.each do |x|
irb(main):026:1* ary << (some_hash.has_key?(x) ? ' ' : some_hash[x])
irb(main):027:1> end
=3D> ["a", "c"]
irb(main):028:0> ary
=3D> [" ", " "]

Please note the parenthesis.
And I have the suspicion that you have the logic backwards, since you
return " " when the hash has the key, and go to the hash when it
doesn't (which will always return nil or the default value). Maybe you
wanted this:

irb(main):033:0> ary =3D []
=3D> []
irb(main):034:0> another_array.each do |x|
irb(main):035:1* ary << (some_hash.has_key?(x) ? some_hash[x]: ' ')
irb(main):036:1> end
=3D> ["a", "c"]
irb(main):037:0> ary
=3D> [1, 3]

Another way of doing this, more idiomatic would be:

irb(main):038:0> ary =3D another_array.map {|x| some_hash.has_key?(x) ?
some_hash[x]: ' '}
=3D> [1, 3]
irb(main):039:0> ary
=3D> [1, 3]


But anyway, you won't get a three element array, since you are
iterating over another_array, which has only two entries. Can you
explain how you should obtain 3 elements in the array? Is it all
elements in the hash that have their key in the another_array? If so:

irb(main):040:0> ary =3D some_hash.map {|k,v| another_array.include?(k) ? v=
: ' '}
=3D> [1, " ", 3]

Hope this helps,

Jesus.
 
M

Matthew K. Williams

Given:
ary = Array.new
some_hash = {'a' => 1, 'b' => 2, 'c' => 3}
another_array = ['a', 'c']

Then:
another_array.each do |x|
ary << some_hash.has_key?(key) ? ' ' : some_hash[key]
end

Expected:
ary should be [1, ' ', 3]

Actual:
[true, false, true]

Question:
Why does that happen?

You need parenthesis around the ternary operation.

The reason being is that << has a higher precedence than ?:, so it
evaluates just the some_hash.has_key?(key), giving a true or a false
value.

In general, while parenthesis are often optional in Ruby, if you're not
sure how something works (or it's not clear), parenthesis are your friend.

Matt
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

It's probably a precedence issue. Looks like << is binding tighter than
?: .

Anyway, you can just do ary = another_array.collect{|x| some_hash[x] ||
' '}
You have to be careful with this, though, because nil and false could be
valid values.

ary = Array.new
some_hash = { 'a' => 1 , 'b' => 2 , 'c' => nil , 'd' => false }
another_array = [ 'a' , 'c' , 'd' , 'e' ]

#if you want nil and false to be valid values, this doesn't do what you
expect
another_array.collect{|x| some_hash[x] || ' ' } # => [1, " ", " ", " "]

#you can set the default to the string, then it will return that if the key
doesn't exist
some_hash.default = ' '
another_array.collect{ |x| some_hash[x] } # => [1, nil, false, " "]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,164
Messages
2,570,898
Members
47,439
Latest member
shasuze

Latest Threads

Top