to flex your problem-solving muscle, I really recommend trying it. Most problems are not too hard. Although the event is already over, you can still collect stars.
first person to collect each star gets 100 pts. • The second person, 99 pts • (…) • The 100th person, 1 pt. After this, you can collect stars but you won’t get any point.
do |i| if input[i] == input[(i + 1) % input.length] solution += input[i].to_i end end puts solution At the end of the loop, the solution variable contains the answer. Let’s print it.
do |i| if input[i] == input[(i + 1) % input.length] solution += input[i].to_i end end puts solution (Many people would write code like this, but in their favorite language)
do |i| if input[i] == input[(i + 1) % input.length] solution += input[i].to_i end end puts solution Slow feedback loop. This works correctly, but the more I learn Ruby, I realize this is an inefficient way of solving the problem. The feedback loop is too slow. You have to write the whole program until you can check if it’s correct or not.
do |i| if input[i] == input[(i + 1) % input.length] solution += input[i].to_i end end puts solution Slow feedback loop. Incorrect result Error If you made a mistake, you’ll only know it when you run the program. Then you have to figure out what’s wrong. Then fix it. Then run it again.
.filter { |a, b| a == b } NoMethodError: undefined method `filter' for #<Enumerator: [1, 2, 2, 3, 3, 3, 4, 5, 5, 1, 1]:each_cons(2)> from (irb):8 from /Users/dtinth/.rvm/rubies/ruby-2.4.1/bin/irb:11:in `<main>' 2.4.1 :009 > As I’m a JavaScript user, I always forget that in Ruby, `filter` is called `select`.
.select { |a, b| a == b }.map(&:first) => [2, 3, 3, 5, 1] 2.4.1 :011 > (input + input[0]).chars.map(&:to_i).each_cons(2) \ .select { |a, b| a == b }.map(&:first) Finally, the last thing I have to do is…
.select { |a, b| a == b }.map(&:first) => [2, 3, 3, 5, 1] 2.4.1 :011 > (input + input[0]).chars.map(&:to_i).each_cons(2) \ .select { |a, b| a == b }.map(&:first).inject(&:+) …to sum em up. I’m gonna inject the + sign between each element. Note from audience: Enumerables also have `sum` method since Ruby 2.4. (Thanks, Michael!)
.select { |a, b| a == b }.map(&:first) => [2, 3, 3, 5, 1] 2.4.1 :011 > (input + input[0]).chars.map(&:to_i).each_cons(2) \ .select { |a, b| a == b }.map(&:first).inject(&:+) => 14 One-liner that solves the problem Very fast feedback loop Get immediate feedback whenever something goes wrong.
.select { |a, b| a == b }.map(&:first) => [2, 3, 3, 5, 1] 2.4.1 :011 > (input + input[0]).chars.map(&:to_i).each_cons(2) \ .select { |a, b| a == b }.map(&:first).inject(&:+) => 14 One-liner that solves the problem Very fast feedback loop Iterative and incremental Instead of having to solve the whole problem at once, I start with the problem, and gradually transform it until a solution is reached.
a == b }.map(&:first).inject(&:+) String#[] String#+ String#chars Enumerable#map Enumerable#each_cons Enumerable#select Enumerable#inject I used a lot of methods to solve this problem. This brings me to the second point:
Compared to many other languages, I can do a lot using only built-in methods, without having to `npm install` anything or import any library. A lot is built-in.
compact, sort_by, and most basic FP tricks found in most languages. Next, I will talk about my favorite tricks. I will skip the most basic functional programming techniques like `map`, `reduce`, `filter`, and will instead focus on the patterns that I use very often.
789 stdin When solving programming challenges, I often have to read an array of numbers from an input file. The first line is the number of elements, and subsequent lines contain each element’s value.
do |i| a[i] = gets.to_i end => [123, 456, 789] Generate array contents programmatically. 3 123 456 789 stdin Most people I know would write a loop like this. Again, in their favorite language.
789] Generate array contents programmatically. 3 123 456 789 stdin But you can also pass a block to Array initializer, and it’s going to run the block for each element. So, that loop has been reduced to a single line.
{} 2.4.1 :002 > tally['b'] => 0 # normal hash: nil 2.4.1 :003 > tally['a'] += 1 => 1 # normal hash: undefined method `+` for nil 2.4.1 :004 > tally => {"a"=>1} Hash can have default value Hashes in Ruby can have a default value, so it’s really easy to do tallying without having to worry about `nil` when reading nonexistent keys from the hash.
{} 2.4.1 :002 > visited[[0, 0]] = true => true Array can be hash keys In Ruby you can also use arrays as hash keys. This is very useful for representing sparse matrices. Also useful when walking on a 2D map, keeping track of which (x, y) coordinates have been visited.
2, 3, 4].combination(2).to_a => [ [1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]] `combination` gives you all possible ways to choose N elements from an array…
2, 3, 4, 5, 6, 7].each_cons(3).to_a => [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7]] For things that are Enumerable, I find myself using `each_cons` a lot.
{ |w| w.chars.first.downcase } .map { |char, words| [char, words.count] } .to_h => {"a"=>17096, "b"=>11070, "c"=>19901, "d"=>10896, "e"=>8736, "f"=>6860, "g"=>6861, "h"=>9027, "i"=>8799, "j"=>1642, "k"=>2281, "l"=>6284, "m"=>12616, "n"=>6780, "o"=>7849, "p"=>24461, "q"=>1152, "r"=>9671, "s"=>25162, "t"=>12966, "u"=>16387, "v"=>3440, "w"=>3944, "x"=>385, "y"=>671, "z"=>949} Enumerable#to_a Enumerable#to_h One thing I especially like about Ruby is that both Arrays and Hashes are Enumerable. And you can convert an Enumerable into both an Array and a Hash.
for: String, Numeric, Rational, Range, Array, Hash, Enumerable, Proc stdlib: matrix, prime, pp For me to solve problems effectively in Ruby, I find myself reading through the API docs of common classes every now and then… …reading through each methods in a class, from top to bottom… I recommend that you do this too — This may sound like an obvious thing to do, but I don’t see developers doing this enough. Me included — I was not aware of the recently-added `sum` method…