On Thursday 07 January 2010, Jagadeesh wrote:
> |On Jan 7, 2:36 pm, Stefano Crocco <stefano.cro... / alice.it> wrote:
> |> On Thursday 07 January 2010, Jagadeesh wrote:
> |> > |hi Gurus,
> |> > |
> |> > |Here my data structure
> |> > |
> |> > |1234 => { 'open' => '1234-1',
> |> > |
> |> > |               'analyzed' => '1234-2',
> |> > |               'feedback' => '1234-3',
> |> > |               'closed' => '1234-4'
> |> > |             }
> |> > |
> |> > |3455 => { 'open' => '3455-1',
> |> > |
> |> > |               'analyzed' => '34552',
> |> > |               'feedback' => '3455-3',
> |> > |               'closed' => '3455-4'
> |> > |             }
> |> > |
> |> > |My task is to display numbers [like 1234 or 3455] if they have
> |> > |('open' OR 'analyzed') AND ('closed' OR 'feedback')  keys. I tried
> |> > |following code
> |> > |
> |> > |puts numbers if   $DATA[pr].has_key?( ( ('closed' || 'feedback')
> |> > |
> |> > |                                                         && ('open'
> |> > | ||
> |> > |
> |> > |'analyzed') ) )
> |> > |
> |> > |I am not sure what is wrong with it but its not testing these
> |> > |conditions and printing all numbers. Please help me understanding
> |> > |has_key method and writing correct condition.
> |> > |
> |> > |Thanks
> |> 
> |> Not tested, but I think the condition should be:
> |> 
> |> ($DATA[pr].has_key?('closed') || $DATA[pr].has_key?('feedback')) &&
> |> ($DATA[pr].has_key?('open') || $DATA[pr].has_key?('analyzed'))
> |> 
> |> Your condition would always have translated to
> |> 
> |> if $DATA[pr].has_key?('open')
> |> 
> |> This happens because ruby first evaluates the argument to has_key? and
> |> because of the way logical operators work. || returns the first operand
> |> which evaluates to true (that is, the first operand which is not false
> |> or nil). This means that:
> |> 'closed' || 'feedback' always gives 'closed'
> |> 'open' || 'analyzed' always gives 'open'
> |> 
> |> On the other hand, the && operator returns the last operand if both
> |> evaluate to true and the value of the one which evaluates to false if
> |> one evaluates to false (if both evaluate to false, it returns the
> |> first). In your case, you had the expression
> |> 
> |> 'closed' && 'open'
> |> 
> |> which evaluates to 'open'.
> |> 
> |> I hope this helps
> |> 
> |> Stefano
> |
> |Thank you so much for crystal clear explanation. Would you show me how
> |I can do it using array? I tried using grep but did not get good
> |result.
> |
> |I want to print if I find (closed or feedback) and (open or analyzed)
> |keys.
> |
> |Thanks

I'm not sure about what you mean by "using array?". Your code clearly uses a 
hash, and Array has no keys and, obviously, no has_key? method. Looking at 
your reply to Jesų¸, I'd say what you want is this:

$DATA.each_pair do |key, value|
  if (value.has_key?('closed') || value.has_key?('feedback')) && 
(value.has_key?('open') || value.has_key?('analyzed'))
    puts key 
  end
end

Hash#each_pair calls the block for each key-value pair. The first argument of 
the block will be set to the key; the second will be set to the value.

If you're sure the values associated with the 'closed', 'feedback', 'open' and 
'analyzed' keys will never be nil or false, you can replace the condition with 
this:

if (value['closed'] || value['feedback']) && (value['open'] || 
value['analyzed'])

This way, instead of checking whether the hash has a given key, you check 
whether or not the associated value is nil. Since Hash returns nil if you ask 
for a non existing key, you'll get a true value (in your case, a string) if 
the key exists and nil if it doesn't. This means you get a true value when 
has_key? would have returned true and a false value (nil) when has_key? would 
have returned false. This, of course, breaks if a key can correspond to a 
value which is false or nil.

Stefano