Ternary Operator and Arrays

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

Felix Dominguez wrote:

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 ||
' '}

Best,

···

--
Marnen Laibow-Koser
http://www.marnen.org
marnen@marnen.org
--
Posted via http://www.ruby-forum.com/\.

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)
irb(main):027:1> end
=> ["a", "c"]
irb(main):028:0> ary
=> [" ", " "]

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

Another way of doing this, more idiomatic would be:

irb(main):038:0> ary = another_array.map {|x| some_hash.has_key?(x) ?
some_hash: ' '}
=> [1, 3]
irb(main):039:0> ary
=> [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 = some_hash.map {|k,v| another_array.include?(k) ? v : ' '}
=> [1, " ", 3]

Hope this helps,

Jesus.

···

On Thu, Nov 19, 2009 at 7:16 PM, Felix Dominguez <fdacat@me.com> wrote:

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

···

On Fri, 20 Nov 2009, Felix Dominguez wrote:

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 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 || ' ' } # => [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 } # => [1, nil, false, " "]

···

On Thu, Nov 19, 2009 at 12:29 PM, Marnen Laibow-Koser <marnen@marnen.org>wrote:

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

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