6

Let's say I have an array of time lengths expressed in minutes:

minutes = [20, 30, 80]

I would like to sum the array contents and output the result in <hours>:<minutes> format. For the example above I expect the result to be 02:10.

Is there any standard Ruby method (i.e. included in core or std-lib) allowing to do this in an one line method chain? (i.e. without using a variable to store an intermediate result). I mean something like:

puts minutes.reduce(:+).foomethod { |e| sprintf('%02d:%02d', e / 60, e % 60) }

What should foomethod be? Object.tap is quite close to what I need, but unfortunately it returns self instead of the block result.

  • 2
    see http://stackoverflow.com/a/7879071/2981429 for an easy way to define such a method; also you could make element a single-element array and use `map`. – max pleaner Nov 14 '16 at 00:14
  • 1
    This answers my question: there is no method doing this in standard Ruby, you have to define your own. – Marco Casprini Nov 14 '16 at 11:43
  • BTW sad. Just with another method on the object class, similar to tap, bue returning the result, many codes would be cleaner, and many chains could be longer without the intermediary temporal variable. – jgomo3 Jun 04 '17 at 14:50

2 Answers2

3

Try this one

puts sprintf('%02d:%02d', *minutes.reduce(:+).divmod(60))
Ursus
  • 29,643
  • 3
  • 33
  • 50
  • Nice solution to the specific example! I didn't remember the `divmod` method, thanks! Anyway it doesn't answer to my initial question "Any standard method similar to tap but returning the block result instead of self?". I think the answer is "no". – Marco Casprini Nov 14 '16 at 11:31
  • Yeah, I think you have to define one on your own :) – Ursus Nov 14 '16 at 11:43
3
proc { |e| sprintf('%02d:%02d', e / 60, e % 60) }.call(minutes.reduce(:+)) #=>"01:00"

or if you prefer lambdas

->(e) { sprintf('%02d:%02d', e / 60, e % 60) }.call(minutes.reduce(:+)) #=>"01:00"

PS: If you want to make these even shorter, you can also use [] and .() for calling a lambda, i.e.

->(e) { sprintf('%02d:%02d', e / 60, e % 60) }.(minutes.reduce(:+)) #=>"01:00"
->(e) { sprintf('%02d:%02d', e / 60, e % 60) }[minutes.reduce(:+)] #=>"01:00"
Rashmirathi
  • 1,744
  • 12
  • 10
  • 1
    Nice solution! It helps me get the answer to my initial question "Any standard method similar to tap but returning the block result instead of self?": I think the answer is "no". BTW, even if it's an one liner, it's not so "linear" as I would like: imagine if you had a much longer method chain! In fact this was just an example. So if I had to choose, I would personally go for clarity, using a variable to store the intermediate result. – Marco Casprini Nov 14 '16 at 11:39