# Dire need for inject\_with\_index

**URL:** <https://www.ruby-forum.com/t/dire-need-for-inject-with-index/102442>\
**Category:** Ruby\
**Created:** [August 15, 2006, 2:17pm UTC](https://www.ruby-forum.com/t/dire-need-for-inject-with-index/102442 "2006-08-15T14:17:29Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![leslieviljoen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/3d9bf3/32.png) [@leslieviljoen](https://www.ruby-forum.com/u/leslieviljoen)\
**Post date:** [August 15, 2006, 2:17pm UTC](https://www.ruby-forum.com/t/dire-need-for-inject-with-index/102442/1 "2006-08-15T14:17:29Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![leslieviljoen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/3d9bf3/32.png) [@leslieviljoen](https://www.ruby-forum.com/u/leslieviljoen)\
**Post date:** [August 15, 2006, 2:17pm UTC](https://www.ruby-forum.com/t/dire-need-for-inject-with-index/102442/2 "2006-08-15T14:17:33Z")

</div>

Hope this helps:

> > require “enumerator”  
> > =\> true
> 
> > module Enumerable  
> > def inject\_with\_index(\*args, &block)  
> > enum\_for(:each\_with\_index).inject(\*args, &block)  
> > end  
> > end  
> > =\> nil
> 
> > (“A”…“D”).inject\_with\_index("") do |str, (let, i)|  
> > ?\> i % 2 == 0 ? str += let : str
> 
> > end  
> > =\> “AC”

James Edward G. II

---

<div class="post-metadata">

**Author:** ![leslieviljoen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/3d9bf3/32.png) [@leslieviljoen](https://www.ruby-forum.com/u/leslieviljoen)\
**Post date:** [August 15, 2006, 2:17pm UTC](https://www.ruby-forum.com/t/dire-need-for-inject-with-index/102442/3 "2006-08-15T14:17:50Z")

</div>

On 8/12/06, James Edward G. II [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > > (“A”…“D”).inject\_with\_index(“”) do |str, (let, i)|  
> > > ?\> i % 2 == 0 ? str += let : str  
> > > end  
> > > =\> “AC”

That most certainly does!  
Les

---

<div class="post-metadata">

**Author:** ![leslieviljoen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/3d9bf3/32.png) [@leslieviljoen](https://www.ruby-forum.com/u/leslieviljoen)\
**Post date:** [August 15, 2006, 2:18pm UTC](https://www.ruby-forum.com/t/dire-need-for-inject-with-index/102442/4 "2006-08-15T14:18:18Z")

</div>

On 8/12/06, Leslie V. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > =\> nil
> > 
> > > > (“A”…“D”).inject\_with\_index(“”) do |str, (let, i)|  
> > > > ?\> i % 2 == 0 ? str += let : str  
> > > > end  
> > > > =\> “AC”

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

---

<div class="post-metadata">

**Author:** ![leslieviljoen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/3d9bf3/32.png) [@leslieviljoen](https://www.ruby-forum.com/u/leslieviljoen)\
**Post date:** [August 15, 2006, 2:18pm UTC](https://www.ruby-forum.com/t/dire-need-for-inject-with-index/102442/5 "2006-08-15T14:18:21Z")

</div>

On Aug 12, 2006, at 3:22 PM, Leslie V. wrote:

> > > > > end  
> > > > > =\> nil
> > > > 
> > > > > (“A”…“D”).inject\_with\_index("") do |str, (let, i)|  
> > > > > ?\> i % 2 == 0 ? str += let : str
> > > > 
> > > > > end  
> > > > > =\> “AC”
> 
> 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 G. II
