[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

coding practise

sempsteen

11/25/2006 9:24:00 AM

Hi all,
First of all sorry for my english.
I'm a Ruby newbie, trying to learn the language from the book, "The
Pragmatic Programmer's Guide". I loved the language very much. Now i
have some question marks about some issues.
If you help me understand this concept i'll be very happy.

1-) What does "Hash#has_key?" actually do?
Why do we need such a method in spite of using the result of "Hash#[]"
method which will return nil for a non-present key.

2-) If we go ahead by the same manner is this a correct way of writing
a program that finds amicable numbers:

class Fixnum
def has_friend?
t1, t2 = 0, 0
1.upto(self / 2) {|i| t1 += i if self % i == 0}
1.upto(t1 / 2) {|i| t2 += i if t1 % i == 0}
if self == t2 and self != t1
return true
else
return false
end
end
def friend
t1, t2 = 0, 0
1.upto(self / 2) {|i| t1 += i if self % i == 0}
1.upto(t1 / 2) {|i| t2 += i if t1 % i == 0}
return t1 if self == t2 and self != t1
end
end

1.upto(1000) {|i| print i, "\t<=>\t", i.friend, "\n" if i.has_friend?}

21 Answers

Paul Lutus

11/25/2006 10:59:00 AM

0

sempsteen wrote:

> Hi all,
> First of all sorry for my english.
> I'm a Ruby newbie, trying to learn the language from the book, "The
> Pragmatic Programmer's Guide". I loved the language very much. Now i
> have some question marks about some issues.
> If you help me understand this concept i'll be very happy.
>
> 1-) What does "Hash#has_key?" actually do?

It returns true if provided with a key that is present in the hash.

> Why do we need such a method in spite of using the result of "Hash#[]"
> method which will return nil for a non-present key.

The method has_key? is faster than using the key to find and return a value,
which is what Hash#[] must do.

> 2-) If we go ahead by the same manner is this a correct way of writing
> a program that finds amicable numbers:
>
> class Fixnum
> def has_friend?
> t1, t2 = 0, 0
> 1.upto(self / 2) {|i| t1 += i if self % i == 0}
> 1.upto(t1 / 2) {|i| t2 += i if t1 % i == 0}

For this section:

> if self == t2 and self != t1
> return true
> else
> return false

Use this:

return self == t2 and self != t1

This produces the same result.

Also, in each of your loops you are testing whether a particular number can
be divided by one with no remainder. The answer is always yes, so for each
calculated value skip this test (start with 2 not 1) and set the initial
value equal to 1.

An article about amicable numbers, with some facts that may improve your
method of calculating them:

http://en.wikipedia.org/wiki/Amica...

About the general topic, it is more efficient to compile an array of divisor
sums and compare in that fashion than to test each number separately as you
are doing. Like this:

-----------------------------------------------

#!/usr/bin/ruby -w

hash = {}

max = 10000

2.upto(max) do |i|
sum = 1
2.upto(i/2) do |j|
sum += j if (i % j) == 0
end
hash[i] = sum
end

hash.keys.sort.each do |i|
a = hash[i]
b = hash[a]
puts "#{a} <-> #{b}" if a != b && b == i
end

-----------------------------------------------

Output:

284 <-> 220
220 <-> 284
1210 <-> 1184
1184 <-> 1210
2924 <-> 2620
2620 <-> 2924
5564 <-> 5020
5020 <-> 5564
6368 <-> 6232
6232 <-> 6368

--
Paul Lutus
http://www.ara...

sempsteen

11/25/2006 1:21:00 PM

0

Thanks for your replies Gareth and Paul.
I've improved return statement as you suggested Paul.
this didn't worked:
return self == t2 and self != t1
but this:
return (self == t2 and self != t1)
and this:
self == t2 and self != t1
worked.

I've also set the sums' initial values to 1 and start the loops from 2
which is more reasonable.
Paul, i understood your code.
Amicable numbers was just an example. I actually want to know where to
use the method pairs like:
has_key? [],
has_friend?, friend
has_sth?, give_that
...

When we call "has_friend?" method it does the same job as "friend"
method except that it returns true or false not the amicable number.
When we call "Hash#has_key?" method it does the same job as "Hash#[]"
method except that it returns true or false, not the value of the
given Hash index.

So if they both do the same job why do i need to search for an
existing value and then call another method that gives the value like:
hsh = {'id' => 10, 'lang' => 'Ruby'}
puts hsh['id'] if hsh.has_key?('id')

I can write it like this:
puts hsh['id'] if hsh['id'] != nil

I hope i could explain it.

On 11/25/06, Paul Lutus <nospam@nosite.zzz> wrote:
> sempsteen wrote:
>
> > Hi all,
> > First of all sorry for my english.
> > I'm a Ruby newbie, trying to learn the language from the book, "The
> > Pragmatic Programmer's Guide". I loved the language very much. Now i
> > have some question marks about some issues.
> > If you help me understand this concept i'll be very happy.
> >
> > 1-) What does "Hash#has_key?" actually do?
>
> It returns true if provided with a key that is present in the hash.
>
> > Why do we need such a method in spite of using the result of "Hash#[]"
> > method which will return nil for a non-present key.
>
> The method has_key? is faster than using the key to find and return a value,
> which is what Hash#[] must do.
>
> > 2-) If we go ahead by the same manner is this a correct way of writing
> > a program that finds amicable numbers:
> >
> > class Fixnum
> > def has_friend?
> > t1, t2 = 0, 0
> > 1.upto(self / 2) {|i| t1 += i if self % i == 0}
> > 1.upto(t1 / 2) {|i| t2 += i if t1 % i == 0}
>
> For this section:
>
> > if self == t2 and self != t1
> > return true
> > else
> > return false
>
> Use this:
>
> return self == t2 and self != t1
>
> This produces the same result.
>
> Also, in each of your loops you are testing whether a particular number can
> be divided by one with no remainder. The answer is always yes, so for each
> calculated value skip this test (start with 2 not 1) and set the initial
> value equal to 1.
>
> An article about amicable numbers, with some facts that may improve your
> method of calculating them:
>
> http://en.wikipedia.org/wiki/Amica...
>
> About the general topic, it is more efficient to compile an array of divisor
> sums and compare in that fashion than to test each number separately as you
> are doing. Like this:
>
> -----------------------------------------------
>
> #!/usr/bin/ruby -w
>
> hash = {}
>
> max = 10000
>
> 2.upto(max) do |i|
> sum = 1
> 2.upto(i/2) do |j|
> sum += j if (i % j) == 0
> end
> hash[i] = sum
> end
>
> hash.keys.sort.each do |i|
> a = hash[i]
> b = hash[a]
> puts "#{a} <-> #{b}" if a != b && b == i
> end
>
> -----------------------------------------------
>
> Output:
>
> 284 <-> 220
> 220 <-> 284
> 1210 <-> 1184
> 1184 <-> 1210
> 2924 <-> 2620
> 2620 <-> 2924
> 5564 <-> 5020
> 5020 <-> 5564
> 6368 <-> 6232
> 6232 <-> 6368
>
> --
> Paul Lutus
> http://www.ara...
>
>

sempsteen

11/25/2006 1:38:00 PM

0

correction:
this also does two method calls
puts hsh['id'] if hsh['id'] != nil

this is the one which i wanted to write, only one method call:
result = hsh['id']
puts result if result != nil

On 11/25/06, sempsteen <sempsteen@gmail.com> wrote:
> Thanks for your replies Gareth and Paul.
> I've improved return statement as you suggested Paul.
> this didn't worked:
> return self == t2 and self != t1
> but this:
> return (self == t2 and self != t1)
> and this:
> self == t2 and self != t1
> worked.
>
> I've also set the sums' initial values to 1 and start the loops from 2
> which is more reasonable.
> Paul, i understood your code.
> Amicable numbers was just an example. I actually want to know where to
> use the method pairs like:
> has_key? [],
> has_friend?, friend
> has_sth?, give_that
> ...
>
> When we call "has_friend?" method it does the same job as "friend"
> method except that it returns true or false not the amicable number.
> When we call "Hash#has_key?" method it does the same job as "Hash#[]"
> method except that it returns true or false, not the value of the
> given Hash index.
>
> So if they both do the same job why do i need to search for an
> existing value and then call another method that gives the value like:
> hsh = {'id' => 10, 'lang' => 'Ruby'}
> puts hsh['id'] if hsh.has_key?('id')
>
> I can write it like this:
> puts hsh['id'] if hsh['id'] != nil
>
> I hope i could explain it.
>
> On 11/25/06, Paul Lutus <nospam@nosite.zzz> wrote:
> > sempsteen wrote:
> >
> > > Hi all,
> > > First of all sorry for my english.
> > > I'm a Ruby newbie, trying to learn the language from the book, "The
> > > Pragmatic Programmer's Guide". I loved the language very much. Now i
> > > have some question marks about some issues.
> > > If you help me understand this concept i'll be very happy.
> > >
> > > 1-) What does "Hash#has_key?" actually do?
> >
> > It returns true if provided with a key that is present in the hash.
> >
> > > Why do we need such a method in spite of using the result of "Hash#[]"
> > > method which will return nil for a non-present key.
> >
> > The method has_key? is faster than using the key to find and return a value,
> > which is what Hash#[] must do.
> >
> > > 2-) If we go ahead by the same manner is this a correct way of writing
> > > a program that finds amicable numbers:
> > >
> > > class Fixnum
> > > def has_friend?
> > > t1, t2 = 0, 0
> > > 1.upto(self / 2) {|i| t1 += i if self % i == 0}
> > > 1.upto(t1 / 2) {|i| t2 += i if t1 % i == 0}
> >
> > For this section:
> >
> > > if self == t2 and self != t1
> > > return true
> > > else
> > > return false
> >
> > Use this:
> >
> > return self == t2 and self != t1
> >
> > This produces the same result.
> >
> > Also, in each of your loops you are testing whether a particular number can
> > be divided by one with no remainder. The answer is always yes, so for each
> > calculated value skip this test (start with 2 not 1) and set the initial
> > value equal to 1.
> >
> > An article about amicable numbers, with some facts that may improve your
> > method of calculating them:
> >
> > http://en.wikipedia.org/wiki/Amica...
> >
> > About the general topic, it is more efficient to compile an array of divisor
> > sums and compare in that fashion than to test each number separately as you
> > are doing. Like this:
> >
> > -----------------------------------------------
> >
> > #!/usr/bin/ruby -w
> >
> > hash = {}
> >
> > max = 10000
> >
> > 2.upto(max) do |i|
> > sum = 1
> > 2.upto(i/2) do |j|
> > sum += j if (i % j) == 0
> > end
> > hash[i] = sum
> > end
> >
> > hash.keys.sort.each do |i|
> > a = hash[i]
> > b = hash[a]
> > puts "#{a} <-> #{b}" if a != b && b == i
> > end
> >
> > -----------------------------------------------
> >
> > Output:
> >
> > 284 <-> 220
> > 220 <-> 284
> > 1210 <-> 1184
> > 1184 <-> 1210
> > 2924 <-> 2620
> > 2620 <-> 2924
> > 5564 <-> 5020
> > 5020 <-> 5564
> > 6368 <-> 6232
> > 6232 <-> 6368
> >
> > --
> > Paul Lutus
> > http://www.ara...
> >
> >
>
>

Vidar Hokstad

11/25/2006 3:10:00 PM

0


sempsteen wrote:
> 1-) What does "Hash#has_key?" actually do?
> Why do we need such a method in spite of using the result of "Hash#[]"
> method which will return nil for a non-present key.

Because you won't know if a "nil" result from Hash#[] means that you
tried to access a non-existing key or if you accessed a key where the
_value_ is nil.

Vidar

Gavin Kistner

11/25/2006 4:02:00 PM

0

sempsteen wrote:
> Thanks for your replies Gareth and Paul.
> I've improved return statement as you suggested Paul.
> this didn't worked:
> return self == t2 and self != t1
> but this:
> return (self == t2 and self != t1)
> and this:
> self == t2 and self != t1
> worked.

The first didn't work due to the very low precedence of the 'and'
operator. This should work:
return self == t2 && self != t1

Although (living with Lua these days) I like the english 'and' and 'or'
operators better than their C-style && and || counterparts, in Ruby I
advise using && and || exclusively, or else be prepared to start
slapping parentheses all over the place.

Paul Lutus

11/25/2006 5:49:00 PM

0

sempsteen wrote:

> correction:
> this also does two method calls
> puts hsh['id'] if hsh['id'] != nil
>
> this is the one which i wanted to write, only one method call:
> result = hsh['id']
> puts result if result != nil

Or:

if(result = hsh[id])
puts result
end

--
Paul Lutus
http://www.ara...

Robert Klemme

11/25/2006 8:45:00 PM

0

On 25.11.2006 11:59, Paul Lutus wrote:
> sempsteen wrote:
>
>> Hi all,
>> First of all sorry for my english.
>> I'm a Ruby newbie, trying to learn the language from the book, "The
>> Pragmatic Programmer's Guide". I loved the language very much. Now i
>> have some question marks about some issues.
>> If you help me understand this concept i'll be very happy.
>>
>> 1-) What does "Hash#has_key?" actually do?
>
> It returns true if provided with a key that is present in the hash.
>
>> Why do we need such a method in spite of using the result of "Hash#[]"
>> method which will return nil for a non-present key.

As others have pointed out if Hash#[] returns nil you do not know
whether the key was in the hash with nil associated or whether it was
missing.

irb(main):001:0> h={}
=> {}
irb(main):002:0> h.has_key? :foo
=> false
irb(main):003:0> h[:foo] = nil
=> nil
irb(main):004:0> h[:foo]
=> nil
irb(main):005:0> h.has_key? :foo
=> true
irb(main):006:0> h.size
=> 1
irb(main):007:0> h
=> {:foo=>nil}

However, in practice this is often negligible since you rarely use nil
as a value in a Hash.

> The method has_key? is faster than using the key to find and return a value,
> which is what Hash#[] must do.

This is wrong: a hash lookup has to be done for both.

Kind regards

robert

Jim Cochrane

11/25/2006 9:11:00 PM

0

On 2006-11-25, Vidar Hokstad <vidar.hokstad@gmail.com> wrote:
>
> sempsteen wrote:
>> 1-) What does "Hash#has_key?" actually do?
>> Why do we need such a method in spite of using the result of "Hash#[]"
>> method which will return nil for a non-present key.
>
> Because you won't know if a "nil" result from Hash#[] means that you
> tried to access a non-existing key or if you accessed a key where the
> _value_ is nil.
>

It also allows for good code readability - 'has_key?': It's pretty
obvious to, e.g., a reviewer what the code wants to do.


--

sempsteen

11/25/2006 9:54:00 PM

0

ok, i get it.
so when we invoke Hash#has_key? it does not responde by calling and
getting the result of Hash#[] method, like if [] responds nil has_key
gives false.

> It also allows for good code readability - 'has_key?': It's pretty
> obvious to, e.g., a reviewer what the code wants to do.

Yes, i agree with you and i also want to code in the same way. I want
to learn the best way of doing this.
Let's say that i want to learn the answer to the ultimate question of
life, the universe and everything.
i don't want to make two calls that first one returns true or false
after 7.5 million years and second one returns the answer another 7.5
million years later if first one returns true.

puts everything.answer if everything.has_answer?

Louis J Scoras

11/26/2006 12:16:00 AM

0

Also, depending on how you created your Hash, the default value might
not be nil. Check out the documentation for the Hash constructors.


--
Lou.