Hi Dirk,

I have translated your code a bit. You can make it much shorter if you

use blocks:

This method selects all factors of a number. Here, I first created a

list of values from 1 to n (1…n). Then only the factors are selected

(the non-factors are filtered).

def find_factors(n)

(1…n).select{|factor| n % factor == 0}

end

This method creates a list of numbers from 1 to max (1…max). Then it

replaces each number n in the list with find_factors(n). That is what

map does:

def find_prime_numbers(max)

(1…max).map{|n| find_factors(n)}

end

The output method is still very tricky, and not elegant. I first changed

factor_list.length.to_s.length to Math.log10(list.length).ceil. Then I

moved it out of the loop, because it is more efficient (it will only be

computed once, and not again in every iteration). I think you know what

log10 is? Well, log10 and then ceil (round up) returns the number of

numbers in a number. So 23 has 2 numbers, and 1234 has 4.

Then I replaced the output variable with inject, and I made some minor

changes like:

factors.length == 2 ? output << “*” : output << " "

to:

output + (factors.length == 2 ? ‘*’ : ’ ')

And

factors.each do | factor |

output << "#{factor} "

end

to:

factors.join(’ ')

and in non-detail mode, I used select and join again.

def output_factor_list(list, detail = false)

if detail

spaces = Math.log10(list.length).ceil

number = 0

list.inject(’’) do |output, factors|

number += 1

output + (factors.length == 2 ? ‘*’ : ’ ‘) +

number.to_s + (’ ’ * (spaces - Math.log10(number + 1).ceil))

+

‘{ ’ + factors.join(’ ') + " } \n"

end

else

‘{ ’ + list.select{|factors| factors.length == 2}.join(’ ') + ’

} ’

end

end

Everything combined:

def find_factors(n)

(1…n).select{|factor| n % factor == 0}

end

def find_prime_numbers(max)

(1…max).map{|n| find_factors(n)}

end

def output_factor_list(list, detail = false)

if detail

spaces = Math.log10(list.length).ceil

number = 0

list.inject(’’) do |output, factors|

number += 1

output + (factors.length == 2 ? ‘*’ : ’ ‘) +

number.to_s + (’ ’ * (spaces - Math.log10(number + 1).ceil))

+

‘{ ’ + factors.join(’ ') + " } \n"

end

else

‘{ ’ + list.select{|factors| factors.length == 2}.join(’ ') + ’

} ’

end

end

print output_factor_list(find_prime_numbers(200), false)

I think most of the changes are from imperative to functional.

Inject/map/select /join really make things simpler, but they are hard to

understand if you haven’t used them.

I hope this was helpful,

Jules