Dire need for inject_with_index

L

Leslie Viljoen

Hi people!

See my nifty little class for converting a few time strings to
seconds. See how the last line of self.seconds reverses an array and
then adds up each part, multiplying the first with 1, the second with
60 and the third with 60*60. So 1:25:20 is a total of one hour, 25
minutes and 20 seconds - all converted to seconds.

Now look how I have to make a magical auto-incrementing counter
variable because inject doesn't provide the element index. Is there a
better way than this? Should I write an inject_with_index?

Les


# Seconder.seconds parses time formats and converts them to seconds,
# returning a string representation. It accepts:
#
# 10:25:05
# 17d (17 days)
# 10h (10 hours)
# 25m
# 5s
# 25:05
# 5

class Seconder
DURATIONS = {'s' => 1, 'm' => 60, 'h' => 60*60, 'd' => 60*60*24}

def self.count
@counter += 1
end

def self.seconds(string)
if string !~
/^\d+$|^\d{1,2}:\d{1,2}$|^\d{1,2}:\d{1,2}:\d{1,2}$|^\d+s$|^\d+h$|^\d+m$|^\d+d$/
return "Format incorrect, try 10:25:05 for hh:mm:ss or 10h for 10 hours"
end

lastChar = string[-1,1]
if DURATIONS.has_key?(lastChar) && string.length > 1

firstChars = string[0..-2]
return (firstChars.to_i * DURATIONS[lastChar]).to_s
end

@counter = 0
string.split(":").reverse.map{|part| part.to_i}.inject{|sum, part|
sum + part * 60 ** count}
end
end
 
L

Leslie Viljoen

What I don't understand about your solution is the "do |str, (let, i)|",
how can you have brackets in there? What does that do?

Your example works as above but I can't get it to work with an array.
Here's what I get:

p [1,3,5].inject_with_index{|sum, (part, index)| sum + part}
=> seconderc.rb:46:in `+': can't convert Fixnum into Array (TypeError)

p [1,3,5].inject_with_index{|sum, part, index| sum + part}
=> [1, 0, 3, 1, 5, 2]


My own inject is a lot clunkier (and takes no params) but seems to work:

def inject_with_index
total = self[0]
index = 1
loop do
break if index == self.length
total = yield(total, self[index], index)
index += 1
end
total
end
public :inject_with_index

p [1,3,5].inject_with_index{|sum, part, index| sum + part}

=> 9


Les
 
J

James Edward Gray II

What I don't understand about your solution is the "do |str, (let,
i)|",
how can you have brackets in there? What does that do?

I used the parens to split the arguments, as you can in Ruby
assignments.
Your example works as above but I can't get it to work with an array.
Here's what I get:

p [1,3,5].inject_with_index{|sum, (part, index)| sum + part}
=> seconderc.rb:46:in `+': can't convert Fixnum into Array (TypeError)

This expression uses inject's default behavior to setup sum, but
remember that elements are now paired with their index. sum is thus
initialized to [1, 0], which blows up your later math. You can fix
this by initializing sum yourself:

[1,3,5].inject_with_index(0) {|sum, (part, index)| sum + part}

James Edward Gray II
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,209
Messages
2,571,088
Members
47,687
Latest member
IngridXxj

Latest Threads

Top