Learn to Program, by Chris Pine

D

Dave Burt

Jan said:
I might continue posting the solutions for the rest of the book if I
decide to keep on reading.

This way I won't develop any bad habits (because hopefully the
solutions will be scrutinized by at least one other person) and it'll
help anyone else reading the book who gets stuck. I doubt the author
of the book will ever get around to publishing the "official"
solutions.

I just looked at the book samples at pragprog and was surprised to see there
are no solutions. That probably means Chris doesn't intend to do official
solutions. Ah, well. Your points are all valid, posting solutions is a good
idea all 'round.

Now, scrutiny and no bad habits. You've only made one mistake, but I'll
point out a couple of things that could be done differently.

That's the same as just "puts" by itself, with no parameters.
input = input.to_i - 1

You can avoid going backwards here by moving "input = input + 1" to the end
of the loop. It often makes things simpler to do the increment at the end
rather than the beginning of a loop.
if input%4 == 0 || input%400 == 0 && input%100 != 0

Here's the mistake.

1984 and 2004 are leap years. OK.
1800 and 1900 are not leap years. Not OK - this program lists them as leap
years.
1600 and 2000 are leap years. OK.

In case this info helps, && binds more closely than ||, so what you've got
is the same as:

if input%4 == 0 || (input%400 == 0 && input%100 != 0)

You should be able to rearrange it to give the correct result for the 1984,
2004, 1800, 1900, 1600 and 2000.

Cheers,
Dave
 
D

Dave Burt

Christian said:
And therefore, we write in Ruby:

99.downto(1) { |bottles| ... }

A good point, Christian, and that syntax is introduced in the very next
chapter after the one we're doing exercises from. It's good to be able to do
things more than one way.

Cheers,
Dave
 
M

Marcus Lunzenauer

Hello!

To sum the digits of an Integer I have got

class Integer
def sum_digits()
sum = 0
n = self
begin sum += n % 10; n /= 10 end while n > 0
sum
end
end


Is there a more Ruby Way to do this? The above method smells of Java,
doesn't it?

Thanks, Marcus
 
J

James Edward Gray II

Hello!

To sum the digits of an Integer I have got

class Integer
def sum_digits()
sum = 0
n = self
begin sum += n % 10; n /= 10 end while n > 0
sum
end
end


Is there a more Ruby Way to do this? The above method smells of
Java, doesn't it?

Here is what I thought of when reading this:
=> 10

Hope that helps.

James Edward Gray II
 
J

Jan_K

Crap, I knew I should have fully tested my code.

Here's the mistake.

1984 and 2004 are leap years. OK.
1800 and 1900 are not leap years. Not OK - this program lists them as leap
years.
1600 and 2000 are leap years. OK.

In case this info helps, && binds more closely than ||, so what you've got
is the same as:

if input%4 == 0 || (input%400 == 0 && input%100 != 0)

You should be able to rearrange it to give the correct result for the 1984,
2004, 1800, 1900, 1600 and 2000.

Yep.

if input%100 != 0 && input%4 == 0 || input%400 == 0


Fix:

-------------------------------------------------------------------------------
puts 'Please enter the starting year'
input = gets.chomp
puts 'Please enter the ending year'
input2 = gets.chomp
puts
puts 'The following are leap years:'

input = input.to_i

while input <= input2.to_i
if input%100 != 0 && input%4 == 0 || input%400 == 0
puts input.to_s
end
input = input + 1
end
-------------------------------------------------------------------------------


1 line shorter at the expense of readability and performance:

-------------------------------------------------------------------------------
puts 'Please enter the starting year'
input = gets.chomp
puts 'Please enter the ending year'
input2 = gets.chomp
puts
puts 'The following are leap years:'

while input.to_i <= input2.to_i
if input.to_i%100 != 0 && input.to_i%4 == 0 || input.to_i%400 == 0
puts input.to_s
end
input = input.to_i + 1
end
-------------------------------------------------------------------------------

I actually did a little benchmark calculating all the leap years for
the next 100 million years (with output going to nul).

Results:

13:26 minutes for the first one.
14:56 minutes for the second one.

The shorter code was 11.16% slower.
 
J

jzakiya

Jan_K said:
Crap, I knew I should have fully tested my code.



Yep.

if input%100 != 0 && input%4 == 0 || input%400 == 0


Fix:

-------------------------------------------------------------------------------
puts 'Please enter the starting year'
input = gets.chomp
puts 'Please enter the ending year'
input2 = gets.chomp
puts
puts 'The following are leap years:'

input = input.to_i

while input <= input2.to_i
if input%100 != 0 && input%4 == 0 || input%400 == 0
puts input.to_s
end
input = input + 1
end
-------------------------------------------------------------------------------


1 line shorter at the expense of readability and performance:

-------------------------------------------------------------------------------
puts 'Please enter the starting year'
input = gets.chomp
puts 'Please enter the ending year'
input2 = gets.chomp
puts
puts 'The following are leap years:'

while input.to_i <= input2.to_i
if input.to_i%100 != 0 && input.to_i%4 == 0 || input.to_i%400 == 0
puts input.to_s
end
input = input.to_i + 1
end
-------------------------------------------------------------------------------

I actually did a little benchmark calculating all the leap years for
the next 100 million years (with output going to nul).

Results:

13:26 minutes for the first one.
14:56 minutes for the second one.

The shorter code was 11.16% slower.


-------------------------------------------------------------------------------
puts 'Please enter the starting year'
input = gets.chomp.to_i # Convert to Integer
puts 'Please enter the ending year'
input2 = gets.chomp.to_i # Convert to Integer
puts
puts 'The following are leap years:'

while input <= input2
if inputi % 100 != 0 && input % 4 == 0 || input % 400 == 0
puts input.to_s
end
input = input + 1
end
 
L

Logan Capaldo

Here is what I thought of when reading this:

=> 10

Hope that helps.

James Edward Gray II

num_s = num.to_s
(0...(num_s.length)).inject(0) { |s, i| s += (num_s - ?0) }

Just to increase confusion and to rely on the properties of ASCII
 
D

Dave Burt

Logan said:
num_s = num.to_s
(0...(num_s.length)).inject(0) { |s, i| s += (num_s - ?0) }


require 'enumerator'
num.to_s.enum_for:)each_byte).inject(0) { |sum, c| sum + c - ?0 }

Or, in Ruby 1.9 (I think):
num.to_s.each_byte.inject(0) { |sum, c| sum + c - ?0 }

Cheers,
Dave
 
J

Jan_K

Solution for the 1st exercise in chapter 8:

(I'm skipping the 2nd exercise - just a bunch of busywork)


-----------------------------------------------------------------------
input = []

while input.last != ''
input.push gets.chomp
end

puts input.sort
-----------------------------------------------------------------------
 
D

Dave Burt

Jan_K said:
Solution for the 1st exercise in chapter 8:

You mean chapter 7.
(I'm skipping the 2nd exercise - just a bunch of busywork)


-----------------------------------------------------------------------
input = []

while input.last != ''
input.push gets.chomp
end

puts input.sort

Very nice!

For exercise 2, writing a program that does something useful is good
practice, and a sort algorithm's simple and therefore a good candidate
if you can get into it.

Or you could just write a game (Blackjack's simple) after you finish
chapter 8.

Cheers,
Dave
 
D

David Bailey

Jan_K said:
I feel like beating the shit out of some punching bag somewhere. Is
this a normal reaction when one is trying to learn to program for the
first time?

Yes, that is a typical outward manifestation, or projection, of the
initial programming learning process. And, no, it won't go away. But
there are a few inner thnings on which one needs to focus, as well. To
wit: start learning to "think outside of the box", be prepared for your
mind to "play tricks" on you, and don't fight the fact that virtually
all of the difficulties you will face at first will be "logic errors" in
your own thinking and not some anomally of the computer. Adopting this
attitude will help you maintain calmness and reduce stress. Programming
is mentally hard work. But the reward is well worth it. Plus, we here
in the programming community are available to help you!
 
J

Jan_K

You mean chapter 7.

I'm actually reading the book and "Arrays and Iterators" is chapter 8.

The book starts with chapter 1 whereas the online tutorial starts with
chapter 0.

Now that I take a look at both it seems like the book is a cleaned-up
and slightly revised version of the tutorial.


Here's the end of chapter 8 from the book:
----------------------------------------------------------------------------------
8.3 A Few Things to Try

• Write the program we talked about at the beginning of this chapter,
one that asks us to type as many words as we want (one word
per line, continuing until we just press Enter on an empty line)
and then repeats the words back to us in alphabetical order. Make
sure to test your program thoroughly; for example, does hitting
Enter on an empty line always exit your program? Even on the
first line? And the second? Hint: There’s a lovely array method
that will give you a sorted version of an array: sort. Use it!

• Rewrite your table of contents program on page 35. Start the
program with an array holding all of the information for your table
of contents (chapter names, page numbers, etc.). Then print out
the information from the array in a beautifully formatted table of
contents.
----------------------------------------------------------------------------------


This the end of the same chapter from the online tutorial:
----------------------------------------------------------------------------------
A Few Things to Try

• Write the program we talked about at the very beginning of this
chapter.
Hint: There's a lovely array method which will give you a sorted
version of an array: sort. Use it!

• Try writing the above program without using the sort method. A large
part of programming is solving problems, so get all the practice you
can!

• Rewrite your Table of Contents program (from the chapter on
methods). Start the program with an array holding all of the
information for your Table of Contents (chapter names, page numbers,
etc.). Then print out the information from the array in a beautifully
formatted Table of Contents.
----------------------------------------------------------------------------------



Some crucially important differences:


From the online tutorial:
----------------------------------------------------------------------------------
languages = ['English', 'German', 'Ruby']

languages.each do |lang|
puts 'I love ' + lang + '!'
puts 'Don\'t you?'
end

puts 'And let\'s hear it for C++!'
puts '...'
----------------------------------------------------------------------------------

From the book:
----------------------------------------------------------------------------------
languages = [' English' , ' Norwegian' , ' Ruby' ]

languages.each do |lang|
puts ' I love ' + lang + ' !'
puts ' Don\' t you?'
end

puts ' And let\' s hear it for Java!'
puts ' <crickets chirp in the distance>'
----------------------------------------------------------------------------------
 
J

Jan_K

Actually, I just flipped through the rest of the book and it starts to
diverge quite a bit from the online tutorial starting with the next
chapter and has 4 additional new chapters.

Here are the table of contents from the book:
http://pragmaticprogrammer.com/titles/fr_ltp/index.html


So if I have any more questions I'll post the exercise instructions
first.

Thanks for your help so far Dave. I was completely stuck in that Flow
Control chapter and pretty much became content that another attempt at
learning programming has successfully failed (just like the previous
half dozen times). It's amazing how hard it is to grasp incredibly
fucking simple concepts for the first time.
 
J

Jan_K

Chapter 9, exercise 1 (page 76)

"Fix up the ask method. That ask method I showed you was alright,
but I bet you could do better. Try to clean it up by removing the
variables good_answer and answer. You’ll have to use return to
exit from the loop. (Well, it will get you out of the whole method,
but it will get you out of the loop in the process.) How do you
like the resulting method? I usually try to avoid using return
(personal preference), but I might make an exception here."


Solution:

--------------------------------------------------------------------------------------
def ask question
while true
puts question
reply = gets.chomp.downcase
if reply == 'yes'
return true
elsif reply == 'no'
return false
else
puts 'Please answer "yes" or "no".'
end
end
end

puts 'Hello, and thank you for...'
puts
ask 'Do you like eating tacos?'
ask 'Do you like eating burritos?'
wets_bed = ask 'Do you wet the bed?'
ask 'Do you like eating chimichangas?'
ask 'Do you like eating sopapillas?'
puts 'Just a few more questions...'
ask 'Do you like drinking horchata?'
ask 'Do you like eating flautas?'
puts
puts 'DEBRIEFING:'
puts 'Thank you for...'
puts
puts wets_bed
--------------------------------------------------------------------------------------
 
B

baumanj

Just one more way, since I haven't seen a solution that takes advantage
of the no-parameter inject call:

1234.to_s.split('').map {|c| c.to_i }.inject {|i,j| i+j }
=> 10
 
D

Dave Burt

Jan_K said:
Actually, I just flipped through the rest of the book and it starts to
diverge quite a bit from the online tutorial starting with the next
chapter and has 4 additional new chapters.

Here are the table of contents from the book:
http://pragmaticprogrammer.com/titles/fr_ltp/index.html


So if I have any more questions I'll post the exercise instructions
first.

Good idea; it's sure to avoid further confusion, and I'm sure Mr. Pine
wouldn't mind this kind of use of his text.
Thanks for your help so far Dave. I was completely stuck in that Flow
Control chapter and pretty much became content that another attempt at
learning programming has successfully failed (just like the previous
half dozen times). It's amazing how hard it is to grasp incredibly
fucking simple concepts for the first time.

You're more than welcome. I'm chuffed that you say this, and very glad
to have helped.

I love teaching programming. I learnt the basics of programming QBasic
in a day, back in grade 6, from a friend (probably a little less than
the equivalent of what you're up to now). And it is difficult and
strange, new vocabulary, "strings", "methods", but it's so useful once
you've got it. A lot of repetitive tasks can be reduced to a brain
exercise by automating them. (See thread, "Does Ruby simplify our tasks
and lives?") And knowing some of these things help you understand
computers (and bend them to your every whim bwahahaha... oh, you're
still reading?)

But mostly it's just fun.

Cheers,
Dave
 
D

Dave Burt

Jan_K said:
Chapter 9, exercise 1 (page 76)
...

Perfect. I can't see any problems at all.

Let me add something, though. Instead of chomping the string, you can
strip it. String#strip removes all whitespace from the beginning and end
of the string, rather than just a single \n from the end.

Cheers,
Dave
 
J

Jan_K

Chapter 9, exercise 2 (page 76)

Old-school Roman numerals. In the early days of Roman numerals,
the Romans didn’t bother with any of this new-fangled subtraction
IX nonsense. No sir, it was straight addition, biggest to littlest -
so 9 was written VIIII, and so on. Write a method that, when
passed an integer between 1 and 3000 (or so), returns a string
containing the proper old-school Roman numeral. In other words,
old_roman_numeral 4 should return 'IIII'. Make sure to test
your method on a bunch of different numbers. Hint: Use the integer
division and modulus methods on page 36.
For reference, these are the values of the letters used:
I = 1 V = 5 X = 10 L = 50
C = 100 D = 500 M = 1000


Solution:
----------------------------------------------------------------
def old_roman_number input

while input < 1 || input > 3999
puts 'Please enter a number between 1 and 3999'
input = gets.chomp.to_i
end

m_mod = input%1000
d_mod = input%500
c_mod = input%100
l_mod = input%50
x_mod = input%10
v_mod = input%5

m_div = input/1000
d_div = m_mod/500
c_div = d_mod/100
l_div = c_mod/50
x_div = l_mod/10
v_div = x_mod/5
i_div = v_mod/1

m = 'M' * m_div
d = 'D' * d_div
c = 'C' * c_div
l = 'L' * l_div
x = 'X' * x_div
v = 'V' * v_div
i = 'I' * i_div

puts m + d + c + l + x + v + i

end

number = gets.chomp.to_i
old_roman_number(number)
----------------------------------------------------------------
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,149
Latest member
Vinay Kumar Nevatia0
Top