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 =3D> { 'open' =3D> '1234-1',
> |> > |
> |> > |               'analyzed' =3D> '1234-2',
> |> > |               'feedback' =3D> '1234-3',
> |> > |               'closed' =3D> '1234-4'
> |> > |             }
> |> > |
> |> > |3455 =3D> { 'open' =3D> '3455-1',
> |> > |
> |> > |               'analyzed' =3D> '34552',
> |> > |               'feedback' =3D> '3455-3',
> |> > |               'closed' =3D> '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
> |>=20
> |> Not tested, but I think the condition should be:
> |>=20
> |> ($DATA[pr].has_key?('closed') || $DATA[pr].has_key?('feedback')) &&
> |> ($DATA[pr].has_key?('open') || $DATA[pr].has_key?('analyzed'))
> |>=20
> |> Your condition would always have translated to
> |>=20
> |> if $DATA[pr].has_key?('open')
> |>=20
> |> 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'
> |>=20
> |> 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
> |>=20
> |> 'closed' && 'open'
> |>=20
> |> which evaluates to 'open'.
> |>=20
> |> I hope this helps
> |>=20
> |> 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=20
hash, and Array has no keys and, obviously, no has_key? method. Looking at=
=20
your reply to Jes=FAs, I'd say what you want is this:

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

Hash#each_pair calls the block for each key-value pair. The first argument =
of=20
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=20
'analyzed' keys will never be nil or false, you can replace the condition w=
ith=20
this:

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

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

Stefano