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 <at> 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

--
Paul Lutus
http://www.arachnoid.com

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

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:

Amicable numbers - Wikipedia

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.arachnoid.com

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

···

On 25.11.2006 11:59, Paul Lutus wrote:

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 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.

--

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:
>
> Amicable numbers - Wikipedia
>
> 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.arachnoid.com
>

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.

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?

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.arachnoid.com

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

···

--
Lou.

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).

···

On 2006-11-25, sempsteen <sempsteen@gmail.com> wrote:

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?

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.

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

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

--
Paul Lutus
http://www.arachnoid.com

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).

···

On 2006-11-26, sempsteen <sempsteen@gmail.com> wrote:

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?

--

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.

···

On 11/26/06, Paul Lutus <nospam@nosite.zzz> wrote:

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.

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

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

--
Paul Lutus
http://www.arachnoid.com

i did it, thanks again!

···

On 11/26/06, sempsteen <sempsteen@gmail.com> 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.

On 11/26/06, Paul Lutus <nospam@nosite.zzz> wrote:
> 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.
>
> >
> > 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?}
>
> 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
>
> --
> Paul Lutus
> http://www.arachnoid.com
>

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.

···

--
Paul Lutus
http://www.arachnoid.com

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.

···

--
Paul Lutus
http://www.arachnoid.com