exercises.rb 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. ## 2.1: Find out how to access files with and without code
  2. ## blocks. What is the benefit of the code block?
  3. ## 2.1.2 with blocks
  4. filename = "users.txt"
  5. File.read(filename) do |file|
  6. file.each_line do |line|
  7. puts line
  8. end
  9. end
  10. # One advantage is, that one does not have to manually call
  11. # `close` on the file object. Similar to reading a file
  12. # using a context manager (with open ... as ...) in Python.
  13. # Another advantage is, that the `file`, as well as the
  14. # `line` are bound and can be accessed
  15. # An advantage is, that `file` and `line` are only bound
  16. # inside the block, and not outside of it. This prevents
  17. # misuse.
  18. # A disadvantage is, that `read` by default reads the whole
  19. # file into memory, which can be a problem for big
  20. # files. This can be avoided using `foreach` of `IO` or
  21. # `File`:
  22. filename = "users.txt"
  23. IO.foreach(filename) do |line|
  24. puts "got line: #{line}"
  25. end
  26. # File inherits from IO.
  27. filename = "users.txt"
  28. File.foreach(filename) do |line|
  29. puts line
  30. end
  31. # The following one reads all at once again:
  32. f = File.read(filename)
  33. f.each_line do |line|
  34. puts line
  35. end
  36. ## 2.1.2 without blocks
  37. filename = "users.txt"
  38. file = File.open(filename, 'r')
  39. file_data = file.read
  40. puts "file content: #{file_data}"
  41. file.close
  42. file = File.open(filename, 'r')
  43. file_data = file.readlines
  44. puts "file content lines: #{file_data}"
  45. file.close
  46. file = File.open(filename, 'r')
  47. file_data = file.readlines.map(&:chomp)
  48. puts "file content lines no newline: #{file_data}"
  49. file.close
  50. fileObj = File.new(filename, 'r')
  51. while (line = fileObj.gets)
  52. puts(line)
  53. end
  54. fileObj.close
  55. puts File.read(filename)
  56. ## 2.2 How would you translate a hash to an array? Can you
  57. ## translate arrays to hashes?
  58. my_hash = {:a => 1, :b => 2, :c => 3}
  59. my_hash.to_a
  60. ## 2.3 Can you iterate through a hash?
  61. my_hash.to_a.each do
  62. |entry|
  63. puts "entry: #{entry}"
  64. end
  65. ## 2.4 You can use Ruby arrays as stacks. What other common
  66. ## data structures do arrays support?
  67. # They can be used as:
  68. # + Stack (push, pop)
  69. # + LinkedList (head, tail)
  70. # + Set (include?, insert, intersection, union)
  71. # + FIFO Queue (push, last), FILO Queue (Stack)
  72. ## 2.5 Print the contents of an array of sixteen numbers,
  73. ## four numbers at a time, using just each. Now, do the same
  74. ## with each_slice in Enumerable.
  75. arr = [0, 1, 2, 3,
  76. 4, 5, 6, 7,
  77. 8, 9, 10, 11,
  78. 12, 13, 14, 15]
  79. # I think no elegant solution is possible, because `each`
  80. # does not give the index of the current element. Seems one
  81. # has to mutate an outside variable.
  82. counter = 0
  83. row = []
  84. arr.each do
  85. |elem|
  86. row.append elem
  87. if (counter % 4) == 3
  88. puts "#{row}"
  89. row = []
  90. end
  91. counter += 1
  92. end
  93. unless arr.empty?
  94. puts "#{row}"
  95. end
  96. # Much easier using `each_slice`:
  97. arr.each_slice(4).to_a.each do |s| puts s end
  98. ## 2.6 The Tree class was interesting, but it did not allow
  99. ## you to specify a new tree with a clean user
  100. ## interface. Let the initializer accept a nested structure
  101. ## of hashes. You should be able to specify a tree like
  102. ## this:
  103. ## {'grandpa' => { 'dad' => {'child 1' => {}, 'child 2' =>
  104. ## {} }, 'uncle' => {'child 3' => {}, 'child 4' => {} } } }.
  105. class Tree
  106. attr_accessor :children, :node_name
  107. def initialize (hash, name=:root)
  108. @children = []
  109. @node_name = name
  110. # Check, if there are more children.
  111. if hash.empty?
  112. @node_name = name
  113. @children = []
  114. else
  115. # If there are more children, then create a tree for
  116. # each child and add them all to children.
  117. hash.to_a.each do
  118. |(name, value)| # block destructuring
  119. child = Tree.new(value, name)
  120. @children.append child
  121. end
  122. end
  123. end
  124. end
  125. family = {
  126. 'grandpa' => {
  127. 'dad' => {
  128. 'child 1' => {},
  129. 'child 2' => {}
  130. },
  131. 'uncle' => {
  132. 'child 3' => {},
  133. 'child 4' => {}
  134. }
  135. }
  136. }
  137. tree = Tree.new(family)
  138. ## 2.7 Write a simple grep that will print the lines of a
  139. ## file having any occurrences of a phrase anywhere in that
  140. ## line. You will need to do a simple regular expression
  141. ## match and read lines from a file. (This is surprisingly
  142. ## simple in Ruby.) If you want, include line numbers.
  143. def simple_grep filename, search_string
  144. File.read(filename).split("\n").each_with_index do
  145. |line, index|
  146. if line.include? search_string
  147. puts "#{index}: #{line}"
  148. end
  149. end
  150. end
  151. simple_grep "user.txt", "a"