Wednesday, February 29, 2012

Seven Languages in Seven Weeks - Ruby Day 2 Self-Study

These are my answers to the 2nd self-study section of Seven Languages in Seven Weeks, enjoy.

Find out how to access files with and without code blocks. What is the benefit of the code block?
file = File.open("hello.txt")
line = file.readline
until line.nil? 
  puts line
  line = file.readline
end
file = File.open("hello.txt")
file.each { |line| puts line }
Latter variant is far more concise. Also, using a code block one avoids dealing with the file object's state.

How would you translate a hash to an array? Can you translate arrays to hashes?
Taking a hash, one can convert it into an array of key-value pairs:
hash.each_pair { |key, value| array.push([key, value]) }
Taking an array, one can map each value to its index (which becomes the key):
array.each_with_index { |item, index| hash[index] = item }

Can you iterate through hash?
Yes, using each_pair (see also example above).

You can use Ruby arrays as stacks. What other common data structures do arrays support?
Ruby arrays provide the push and pop stack operations. To use an array as a queue, use push to enqueue and shift to dequeue items. List operations are supported using methods like first, insert, etc.

Print the contents of an array of sixteen numbers, four numbers at the time, using just each.
i = 1
array.each do |x|
  print x, ' '
  puts if i % 4 == 0
  i += 1
end

Now, do the same with each_slice in Enumerable.
array.each_slice(4) { |slice| p slice }

The Tree class was interesting, but it did not allow you to specify a new tree with a clean user interface. Let the initializer accept a nested structure of hashes. You should be able to specify a tree like this: {'grandpa' => {'dad' => {'child 1' => {}, 'child 2' => {} }, 'uncle' => {'child 3' => {}, 'child 4' => {} } } }.
class Tree
  attr_accessor :children, :node_name
  
  def initialize (name, children={}) 
    @node_name = name
    @children = []
    children.each_pair {|key, val| @children << Tree.new(key, val) }
  end
  
  def visit_all (&block)
    visit &block
    children.each {|c| c.visit_all &block}
  end
  
  def visit (&block)
    block.call self
  end
end
Write a simple grep that will print the lines of a file having any occurrences of a phrase anywhere in that line. You will need to do a simple regular expression match and read lines from a file. (This is surprisingly simple simple in Ruby.) If you want, include line numbers.
def grep (pattern, filename)
  f = File.open(filename)
  f.each {|line| puts "#{f.lineno}: #{line}" if line =~ /#{pattern}/}
end

Monday, February 27, 2012

Seven Languages in Seven Weeks - Ruby Day 1 Self-Study

I started reading Seven Languages in Seven Weeks. I'll be posting some of my answers to the self-study section at the end of each chapter, mainly for self-documentation.

Some links:

Print the string "Hello, world."
>> puts "Hello, World"
Hello, World
=> nil

For the string "Hello, Ruby", find the index of the word "Ruby"
>> "Hello, Ruby".index("Ruby")
=> 7

Print your name ten times
>> 10.times { puts "ant0inet" }
ant0inet
ant0inet
ant0inet
ant0inet
ant0inet
ant0inet
ant0inet
ant0inet
ant0inet
ant0inet
=> 10

Run a Ruby program from a file.
$ cat > hello_world.rb << EOF
> #!/usr/bin/env ruby
> puts "Hello, world."
> EOF
$ ruby hello_world.rb 
Hello, world.

Write a program that picks a random number. Let a player guess the number, telling the player whether the guess is too low or too high.
#!/usr/bin/env ruby

random_num = rand(10) + 1
puts "Enter your guess:"
guess = gets.to_i
until guess == random_num
  if guess < random_num
    puts "too low"
  else
    puts "too high"
  end
  guess = gets.to_i
end 
puts "correct"