123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- ## 2.1: Find out how to access files with and without code
- ## blocks. What is the benefit of the code block?
- ## 2.1.2 with blocks
- filename = "users.txt"
- File.read(filename) do |file|
- file.each_line do |line|
- puts line
- end
- end
- # One advantage is, that one does not have to manually call
- # `close` on the file object. Similar to reading a file
- # using a context manager (with open ... as ...) in Python.
- # Another advantage is, that the `file`, as well as the
- # `line` are bound and can be accessed
- # An advantage is, that `file` and `line` are only bound
- # inside the block, and not outside of it. This prevents
- # misuse.
- # A disadvantage is, that `read` by default reads the whole
- # file into memory, which can be a problem for big
- # files. This can be avoided using `foreach` of `IO` or
- # `File`:
- filename = "users.txt"
- IO.foreach(filename) do |line|
- puts "got line: #{line}"
- end
- # File inherits from IO.
- filename = "users.txt"
- File.foreach(filename) do |line|
- puts line
- end
- # The following one reads all at once again:
- f = File.read(filename)
- f.each_line do |line|
- puts line
- end
- ## 2.1.2 without blocks
- filename = "users.txt"
- file = File.open(filename, 'r')
- file_data = file.read
- puts "file content: #{file_data}"
- file.close
- file = File.open(filename, 'r')
- file_data = file.readlines
- puts "file content lines: #{file_data}"
- file.close
- file = File.open(filename, 'r')
- file_data = file.readlines.map(&:chomp)
- puts "file content lines no newline: #{file_data}"
- file.close
- fileObj = File.new(filename, 'r')
- while (line = fileObj.gets)
- puts(line)
- end
- fileObj.close
- puts File.read(filename)
- ## 2.2 How would you translate a hash to an array? Can you
- ## translate arrays to hashes?
- my_hash = {:a => 1, :b => 2, :c => 3}
- my_hash.to_a
- ## 2.3 Can you iterate through a hash?
- my_hash.to_a.each do
- |entry|
- puts "entry: #{entry}"
- end
- ## 2.4 You can use Ruby arrays as stacks. What other common
- ## data structures do arrays support?
- # They can be used as:
- # + Stack (push, pop)
- # + LinkedList (head, tail)
- # + Set (include?, insert, intersection, union)
- # + FIFO Queue (push, last), FILO Queue (Stack)
- ## 2.5 Print the contents of an array of sixteen numbers,
- ## four numbers at a time, using just each. Now, do the same
- ## with each_slice in Enumerable.
- arr = [0, 1, 2, 3,
- 4, 5, 6, 7,
- 8, 9, 10, 11,
- 12, 13, 14, 15]
- # I think no elegant solution is possible, because `each`
- # does not give the index of the current element. Seems one
- # has to mutate an outside variable.
- counter = 0
- row = []
- arr.each do
- |elem|
- row.append elem
- if (counter % 4) == 3
- puts "#{row}"
- row = []
- end
- counter += 1
- end
- unless arr.empty?
- puts "#{row}"
- end
- # Much easier using `each_slice`:
- arr.each_slice(4).to_a.each do |s| puts s end
- ## 2.6 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 (hash, name=:root)
- @children = []
- @node_name = name
- # Check, if there are more children.
- if hash.empty?
- @node_name = name
- @children = []
- else
- # If there are more children, then create a tree for
- # each child and add them all to children.
- hash.to_a.each do
- |(name, value)| # block destructuring
- child = Tree.new(value, name)
- @children.append child
- end
- end
- end
- end
- family = {
- 'grandpa' => {
- 'dad' => {
- 'child 1' => {},
- 'child 2' => {}
- },
- 'uncle' => {
- 'child 3' => {},
- 'child 4' => {}
- }
- }
- }
- tree = Tree.new(family)
- ## 2.7 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 in Ruby.) If you want, include line numbers.
- def simple_grep filename, search_string
- File.read(filename).split("\n").each_with_index do
- |line, index|
- if line.include? search_string
- puts "#{index}: #{line}"
- end
- end
- end
- simple_grep "user.txt", "a"
|