Coding practise

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

sempsteen <sempsteen gmail.com> writes:

Hi,

I don’t know too much about amicable numbers, but I can answer the first
one…

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.

hsh = { :a => 5, :b => nil }

hsh.has_key? :a # => true
hsh[:a] # => 5
hsh.has_key? :b # => true
hsh[:b] # => nil
hsh.has_key? :c # => false
hsh[:c] # => false

Note that when the value of the hash item is nil or false, you’ll get a
difference between #as_key? and #[]

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:

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

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

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.

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

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.

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

On 2006-11-25, Vidar H. [email protected] 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.

On 25.11.2006 11:59, Paul L. wrote:

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

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

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?

Yep, now i know that my Hash example is a different matter.

The fix:
change ‘has_answer’ to store the answer (privately) after calculating it and
‘answer’ to simply retrieve that answer if it has been created.

Where do you suggest to store the value for my amicable numbers example?

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

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

I want a “has_friend?” method and “friend” method. One for searching
for the existing of given number, other one is for getting the value
of the friend of that number. And i want those methods inside “Fixnum”
class structure, like as instance methods.
when i call has_friend? method it will store its value to some kind of
variable, but return true or false and, when i call friend method it
will get the stored value.
But what must be that some kind of variable that holds the value?

  • class variable
  • instance variable
  • global
  • or what?

On 2006-11-25, sempsteen [email protected] wrote:

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?

Easy: puts 42

Seriously, I’d say in your above example that the class that
‘everything’ is an instance of is poorly designed - if ‘has_answer’ does
the same (redundant) calculation as ‘answer’. (If it doesn’t, then
the design is fine and you have to be very, very patient.) The fix:
change ‘has_answer’ to store the answer (privately) after calculating it
and
‘answer’ to simply retrieve that answer if it has been created.

But your hash example is a different matter - if you access the hash a
large number of times and there is redundancy re. ‘has_key’ vs. [] and
performance is important, it may be worth it to change the app. to not
call has_key. But if you leave it as is and you find that it performs
acceptably, then IIABDFI (if it ain’t broke, don’t fix it).

sempsteen wrote:

Yep, now i know that my Hash example is a different matter.

The fix:
change ‘has_answer’ to store the answer (privately) after calculating it
and ‘answer’ to simply retrieve that answer if it has been created.

Where do you suggest to store the value for my amicable numbers example?

Use my previously posted code as a starting point, the one that uses a
precalculated hash of divisor sums.

Create an instance of your class and accept a value for maximum number
if
the user offers one. Precalculate the sums of divisors as you initialize
the class, up to this provided maximum number, or a default value.

If the user provides an argument that is our of range of the
precalculated
values, just calculate additional values and add them to the existing
hash,
then return the result to the user.

2.upto(self / 2) {|i| t1 += i if self % i == 0}
2.upto(t1 / 2) {|i| t2 += i if t1 % i == 0}
return t1 if self == t2 && self != t1

end
end

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

Please abandon this code. It is extremely inefficient.

I want a “has_friend?” method and “friend” method. One for searching
for the existing of given number, other one is for getting the value
of the friend of that number. And i want those methods inside “Fixnum”
class structure, like as instance methods.

No, you do not. You want to write a separate class for handling this
specialized kind of problem, not part of Fixnum. And yo do not want to
recalculate the entire divisor set over again for each entered argument.

when i call has_friend? method it will store its value to some kind of
variable, but return true or false and, when i call friend method it
will get the stored value.
But what must be that some kind of variable that holds the value?

A hash table, as in my posted example. And you do not want to make
this
amicable detector capability part of Fixnum, any more than you would
want
to make a numerical integral solver part of Fixnum – it’s just not
appropriate to be included in the class.


#!/usr/bin/ruby -w

class Amicable

def initialize(max = 1000)
@max = 2
fill_hash(max)
end

def fill_hash(max)
@hash ||= {}
if(max > @max)
2.upto(max) do |i|
sum = 1
2.upto(i/2) do |j|
sum += j if (i % j) == 0
end
@hash[i] = sum
end
@max = max
end
end

def comp_amicable(n)
fill_hash(n)
q = @hash[n]
return @hash[n] if n == @hash[q] && n != q
return false
end

def has_friend?(n)
return comp_amicable(n) != false
end

def friend(n)
return comp_amicable(n)
end

end

test the class:

max = 10000

amic = Amicable.new(max)

2.upto(max) do |i|
j = amic.friend(i)
puts “#{i} <-> #{j}” if j
end


Output:

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

Thanks Paul.
I knew that my code was inefficient. That’s the reason why i’m here. I
thought, because i’m dealing with numbers i can define handling
methods inside Fixnum (neglecting Bignum).
Now i will write it again in a different class as your code by myself.

i did it, thanks again!

sempsteen wrote:

Thanks Paul.
I knew that my code was inefficient. That’s the reason why i’m here. I
thought, because i’m dealing with numbers i can define handling
methods inside Fixnum (neglecting Bignum).
Now i will write it again in a different class as your code by myself.

I am certain you can improve on my code. There are a number of
efficiencies
that I didn’t include that would improve the performance of the
algorithm,
like the prime-number strategy outlined here:

Although that strategy sometimes fails, it should give you some ideas
about
improving the method.

sempsteen wrote:

i did it, thanks again!

Usenet is a door that swings both ways. This thread may last decades in
Usenet archives and may be accessed again and again by students and
others.

What am I saying? I am saying you might consider posting your final
code,
for the benefit of all who might try to solve the same problem in the
future.

On 2006-11-26, sempsteen [email protected] wrote:

Yep, now i know that my Hash example is a different matter.

The fix:
change ‘has_answer’ to store the answer (privately) after calculating it and
‘answer’ to simply retrieve that answer if it has been created.

Where do you suggest to store the value for my amicable numbers example?

Looks like Paul has given you the answer (which I appreciate, since I
don’t have the time to give a good answer).