1

Find the longest word.

longest = %w{cat sheep bear}.inject do |memo, word|
  memo.length > word.length ? memo : word
end

I'm guessing that memo will start with the value "cat" since inject did not receive any argument. I'm also guessing that the first value for word will be sheep, followed by word and bear.

I'm not following what is going on in the block and its syntax. I would appreciate if someone could elaborate.

sawa
  • 165,429
  • 45
  • 277
  • 381
Ari
  • 45
  • 5

2 Answers2

5

1. So I'm guessing that memo will start off with the value cat seeing as inject has no argument passed to it.

Documentation says:

If you do not explicitly specify an initial value for memo, then the first element of collection is used as the initial value of memo.

2. I'm also guessing that the first word will then be sheep..then next word, bear.

You can use puts to inspect each stage bar the final assignment, but that's just the return value of the inject method:

longest = %w{ cat sheep bear }.inject do |memo, word|
  puts "memo is currently #{memo}", 
       "word is currently #{word}",
       "-----------------------"
  memo.length > word.length ? memo : word
end

#memo is currently cat
#word is currently sheep
#-----------------------
#memo is currently sheep
#word is currently bear
#-----------------------

longest #=> "sheep"

Another way

Finally another more Rubyish way to get the longest word:

%w{ cat sheep bear }.max_by(&:length) #=> "sheep"
Community
  • 1
  • 1
Sagar Pandya
  • 9,323
  • 2
  • 24
  • 35
  • I looked up `max_by` in the documentation. They used the the following example: – Ari Jun 19 '17 at 08:09
  • `a = %w(albatross dog horse) a.max_by { |x| x.length }` – Ari Jun 19 '17 at 08:10
  • Which i understand..if you don't mind, could you please explain how passing `(&:length)` as argument works. I do not understand `&:` and how it can be used as argument? thx – Ari Jun 19 '17 at 08:15
  • 1
    @codebreeze this is called [`Symbol#to_proc`](https://ruby-doc.org/core-2.2.0/Symbol.html#method-i-to_proc) and what it does is converts a given symbol to a proc similar to `Proc.new { |var| var.[method_name_from_symbol] }` so in this case `Proc.new { |var| var.length }`. It was a syntactical monkey patch that caught on and was consumed into ruby core in 1.8.7 because of it's popularity – engineersmnky Jun 19 '17 at 13:17
  • @engineersmnky Please check my reasoning. Is `:length = Proc.new { |var| var.length}` and then one makes use of the ampersand to tell the `max_by` method not to ignore the symbol/proc? – Ari Jun 19 '17 at 20:27
  • @codebreeze `max_by` accepts a block and yields each argument to this block .`&` indicates a method call of `to_proc` e.g. `&:length` actually means `:length.to_proc`. `Symbol#to_proc` creates a proc as described above. This proc now becomes the "block" passed to `max_by` and `max_by` yields the values to this block of code. I hope this is clear – engineersmnky Jun 19 '17 at 20:33
  • @codebreeze another interesting use of `to_proc` is `Method#to_proc` where as instead of calling the method on the yielded value the yielded value is passed to the method instead as an argument i.e. `def inspect_this(a); puts a.inspect; end` then it can be called like `['a','b','c'].each(&method(:inspect_this))` and it will pass each element to the method rather than calling the method on the element – engineersmnky Jun 19 '17 at 20:43
1

With inject, the block should return the new value for memo

In this case the conditional operator is being used to return one of two values: either the existing value of memo if memo is longer than the current word or word if the current word is longer or the same length. i.e. it's a way of working through the list of words maintaining the longest word so far in memo (or most recently seen word when the lengths are tied.)

Then at the end inject returns the final value of memo.

mikej
  • 65,295
  • 17
  • 152
  • 131
  • 1
    Ahh i see. I didn't know about this (`? : `) operator..now it makes a lot more sense.. `if_this_is_a_true_value ? then_the_result_is_this : else_it_is_this` – Ari Jun 19 '17 at 07:37