Find index of first non zeo value in array

with :
array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

I wrote :
array.index(array.detect {|x| x > 0}) => 15

is there a better and simpler way to do it ?
thanks

joss

In that case, it is simpler to use an external counter, i think :

c = 0
array.each{|v| break if not v.zero?; c += 1}
puts c # => 15

···

Le dimanche 26 novembre 2006 15:00, Josselin a écrit :

with :
array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0]

I wrote :
array.index(array.detect {|x| x > 0}) => 15

is there a better and simpler way to do it ?
thanks

joss

Hi,

From: Josselin <josselin@wanadoo.fr>
Reply-To: ruby-talk@ruby-lang.org
To: ruby-talk@ruby-lang.org (ruby-talk ML)
Subject: find index of first non zeo value in array
Date: Sun, 26 Nov 2006 23:00:10 +0900

with :
array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

I wrote :
array.index(array.detect {|x| x > 0}) => 15

is there a better and simpler way to do it ?
thanks

joss

How about this:

array.index((array-[0])[0])

Regards,

Park Heesob

···

_________________________________________________________________
Don't just search. Find. Check out the new MSN Search! http://search.msn.com/

Did we have a solution with #inject already? In case we didn't:

irb(main):001:0> require 'enumerator'
=> true
irb(main):002:0> a=Array.new(10,0) << 666 << 0
=> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 666, 0]
irb(main):003:0> a.to_enum(:each_with_index).inject(nil) {|pp,(x,i)| break i unless x == 0}
=> 10
irb(main):004:0> a[0..5]
=> [0, 0, 0, 0, 0, 0]
irb(main):005:0> a[0..5].to_enum(:each_with_index).inject(nil) {|pp,(x,i)| break i unless x == 0}
=> nil

Kind regards

  robert

···

On 26.11.2006 14:59, Josselin wrote:

with :
array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

I wrote :
array.index(array.detect {|x| x > 0}) => 15

is there a better and simpler way to do it ?
thanks

# uber_nasty_for_laughs.rb
array.to_s.split(/[1-9]/)[0].length

···

On 11/26/06, Josselin <josselin@wanadoo.fr> wrote:

with :
array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0]

I wrote :
array.index(array.detect {|x| x > 0}) => 15

is there a better and simpler way to do it ?
thanks

joss

Hi --

···

On Sun, 26 Nov 2006, Olivier wrote:

Le dimanche 26 novembre 2006 15:00, Josselin a écrit :

with :
array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0]

I wrote :
array.index(array.detect {|x| x > 0}) => 15

is there a better and simpler way to do it ?
thanks

joss

In that case, it is simpler to use an external counter, i think :

c = 0
array.each{|v| break if not v.zero?; c += 1}
puts c # => 15

Or:

   c = array.each_with_index {|e,i| break i unless e.zero? }

David

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

with :
array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0]

I wrote :
array.index(array.detect {|x| x > 0}) => 15

is there a better and simpler way to do it ?
thanks

joss

In that case, it is simpler to use an external counter, i think :

c = 0
array.each{|v| break if not v.zero?; c += 1}
puts c # => 15

You can ask Ruby to maintain the counter, if you want:

>> require "enumerator"
=> true
>> array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0,
?> 0, 0, 0, 0, 0, 0]
=> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>> result = array.enum_with_index.find { |n, i| n.nonzero? }.last rescue nil
=> 15
>> array.slice!(15, 1)
=> [21]
>> array
=> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>> result = array.enum_with_index.find { |n, i| n.nonzero? }.last rescue nil
=> nil

James Edward Gray II

···

On Nov 26, 2006, at 8:54 AM, Olivier wrote:

Le dimanche 26 novembre 2006 15:00, Josselin a écrit :

Robert Klemme wrote:

Did we have a solution with #inject already? In case we didn't:

irb(main):001:0> require 'enumerator'
=> true
irb(main):002:0> a=Array.new(10,0) << 666 << 0
=> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 666, 0]
irb(main):003:0> a.to_enum(:each_with_index).inject(nil) {|pp,(x,i)| break i unless x == 0}
=> 10

sub 'inject(nil) {|pp,(x,i)|', 'find {|x,i|'

But I vote for adding to Enumerable or Array. #index_where or #find_by or something. (My preference over alias-and-delegate.)

Devin

Not a generic way, but pretty good for this specific problem.

Regards,
Pradeep

···

On Sunday 26 November 2006 21:22, Park Heesob wrote:

Hi,

>From: Josselin <josselin@wanadoo.fr>
>Reply-To: ruby-talk@ruby-lang.org
>To: ruby-talk@ruby-lang.org (ruby-talk ML)
>Subject: find index of first non zeo value in array
>Date: Sun, 26 Nov 2006 23:00:10 +0900
>
>with :
>array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0,
> 0, 0, 0, 0, 0]
>
>I wrote :
>array.index(array.detect {|x| x > 0}) => 15
>
>is there a better and simpler way to do it ?
>thanks
>
>joss

How about this:

array.index((array-[0])[0])

Regards,

Park Heesob

_________________________________________________________________
Don't just search. Find. Check out the new MSN Search!
http://search.msn.com/

Robert Klemme wrote:

···

On 26.11.2006 14:59, Josselin wrote:
> with :
> array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0,
> 0, 0, 0, 0, 0]
>
> I wrote :
> array.index(array.detect {|x| x > 0}) => 15
>
> is there a better and simpler way to do it ?
> thanks

Did we have a solution with #inject already?

array.inject(0){|i,e| if e>0; break i else i+1 end}

No, I'm wrong; that leaves c == a if there's no non-zero element.
Ignore.

David

···

On Mon, 27 Nov 2006, dblack@wobblini.net wrote:

Or:

c = array.each_with_index {|e,i| break i unless e.zero? }

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

Hi --

···

On Mon, 27 Nov 2006, James Edward Gray II wrote:

On Nov 26, 2006, at 8:54 AM, Olivier wrote:

Le dimanche 26 novembre 2006 15:00, Josselin a écrit :

array.index(array.detect {|x| x > 0}) => 15

c = 0
array.each{|v| break if not v.zero?; c += 1}
puts c # => 15

result = array.enum_with_index.find { |n, i| n.nonzero? }.last rescue nil

That seems kind of like a reinvention of Array#index, though. It also
has the usual problem with rescue, i.e., that you might rescue the
wrong thing (if nonzero? is mistyped or whatever). Do you see an
advantage to doing it this way, rather than the index/detect way?
(I'm being lazy and not benchmarking them....)

David

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

William James wrote:

Robert Klemme wrote:
> > with :
> > array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0,
> > 0, 0, 0, 0, 0]
> >
> > I wrote :
> > array.index(array.detect {|x| x > 0}) => 15
> >
> > is there a better and simpler way to do it ?
> > thanks
>
> Did we have a solution with #inject already?

array.inject(0){|i,e| if e>0; break i else i+1 end}

array.inject(0){|i,e| break i if e>0; i+1 }

···

> On 26.11.2006 14:59, Josselin wrote:

Well, it only walks the Array once. The other way walks it once for detect() and again for index(). I agree that it's not sexy code though.

I believe there has been talk in the past of having index() take a block for matching. That would solve this problem ideally. I can submit an RCR if people think it's worth it, but I'm pretty sure Matz said it was OK last time it came up... (Correct me if I am wrong!)

James Edward Gray II

···

On Nov 26, 2006, at 9:53 AM, dblack@wobblini.net wrote:

On Mon, 27 Nov 2006, James Edward Gray II wrote:

On Nov 26, 2006, at 8:54 AM, Olivier wrote:

Le dimanche 26 novembre 2006 15:00, Josselin a écrit :

array.index(array.detect {|x| x > 0}) => 15

c = 0
array.each{|v| break if not v.zero?; c += 1}
puts c # => 15

result = array.enum_with_index.find { |n, i| n.nonzero? }.last rescue nil

That seems kind of like a reinvention of Array#index, though. It also
has the usual problem with rescue, i.e., that you might rescue the
wrong thing (if nonzero? is mistyped or whatever). Do you see an
advantage to doing it this way, rather than the index/detect way?
(I'm being lazy and not benchmarking them....)

Using a regular expression ...

array.join =~ /[^0]/

The inject method is faster, though, because you do not have to create
a string. I'm assuming that the "array.index((array-[0])[0])" solution
suffers from the same problem -- creating another object under the
covers ...

$ ruby tmp.rb
                user system total real
inject 2.874000 0.000000 2.874000 ( 2.884000)
index 0.721000 0.000000 0.721000 ( 0.731000)
regexp 3.755000 0.000000 3.755000 ( 3.765000)

Wow! Looks like the "index" method wins hands down.

But mine is still shorter :wink:

TwP

···

On 11/27/06, William James <w_a_x_man@yahoo.com> wrote:

William James wrote:
> Robert Klemme wrote:
> > On 26.11.2006 14:59, Josselin wrote:
> > > with :
> > > array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0,
> > > 0, 0, 0, 0, 0]
> > >
> > > I wrote :
> > > array.index(array.detect {|x| x > 0}) => 15
> > >
> > > is there a better and simpler way to do it ?
> > > thanks
> >
> > Did we have a solution with #inject already?
>
> array.inject(0){|i,e| if e>0; break i else i+1 end}

array.inject(0){|i,e| break i if e>0; i+1 }

Hi --

array.index(array.detect {|x| x > 0}) => 15

c = 0
array.each{|v| break if not v.zero?; c += 1}
puts c # => 15

result = array.enum_with_index.find { |n, i| n.nonzero? }.last rescue nil

That seems kind of like a reinvention of Array#index, though. It also
has the usual problem with rescue, i.e., that you might rescue the
wrong thing (if nonzero? is mistyped or whatever). Do you see an
advantage to doing it this way, rather than the index/detect way?
(I'm being lazy and not benchmarking them....)

Well, it only walks the Array once. The other way walks it once for detect() and again for index(). I agree that it's not sexy code though.

I believe there has been talk in the past of having index() take a block for matching. That would solve this problem ideally. I can submit an RCR if people think it's worth it, but I'm pretty sure Matz said it was OK last time it came up... (Correct me if I am wrong!)

Yes, there's an accepted RCR for it. That will be good.

This exchange relates to something I've been pondering for a while,
namely: is there always (or very, very often) an inverse relation
between elegance of code and efficiency? I don't mean to sound like
I'm singling out your example -- on the contrary, it seems that over
and over we see cases where a nice concise solution bombs out compared
to one that's longer, possibly less clear (I still can't read the
enum* stuff as quickly and confidently as I can read the regular
Enumerable stuff, though that may just be due to stupidity), but
faster.

I haven't really documented or studied this in detail, though it does
seem to keep happening. It might be interesting to look into further.

David

···

On Mon, 27 Nov 2006, James Edward Gray II wrote:

On Nov 26, 2006, at 9:53 AM, dblack@wobblini.net wrote:

On Mon, 27 Nov 2006, James Edward Gray II wrote:

On Nov 26, 2006, at 8:54 AM, Olivier wrote:

Le dimanche 26 novembre 2006 15:00, Josselin a écrit :

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

James Edward Gray II wrote:

I believe there has been talk in the past of having index() take a block for matching.

Meh... talk schmalk...

class Array
   alias orig_index index
   def index(*args)
     return orig_index(*args) unless block_given?
     (0...length).each do |i|
       return i if yield self[i]
     end
     nil
   end
end

array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
array.index 21 #=> 15
array.index {|n| n.nonzero? } #=> 15

Devin

IIRC Matz accepted it straight into 1.9. It's implemented there now:

$ ruby9 -ve 'p [0,0,0,15,0].index { |e| e > 0 }'
ruby 1.9.0 (2006-11-26 patchlevel 0) [i686-linux]
3

···

On Mon, 2006-11-27 at 01:00 +0900, James Edward Gray II wrote:

I believe there has been talk in the past of having index() take a
block for matching. That would solve this problem ideally. I can
submit an RCR if people think it's worth it, but I'm pretty sure Matz
said it was OK last time it came up... (Correct me if I am wrong!)

--
Ross Bamford - rosco@roscopeco.REMOVE.co.uk

Just saw this..

@ ruby conf, there were talks about the speed of ruby's regex

Being that ruby was the first language I picked up, I'm curious as to
how other languages(such as perl) compare from a performance
standpoint with your examples.

I'm not expecting perl to be slower an any scenerio, but is the perl
index() quicker or slower than a perl regex? If the latter, is the
performance ratio proportional to that of our ruby examples?

···

On 11/27/06, Tim Pease <tim.pease@gmail.com> wrote:

On 11/27/06, William James <w_a_x_man@yahoo.com> wrote:
>
> William James wrote:
> > Robert Klemme wrote:
> > > On 26.11.2006 14:59, Josselin wrote:
> > > > with :
> > > > array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0,
> > > > 0, 0, 0, 0, 0]
> > > >
> > > > I wrote :
> > > > array.index(array.detect {|x| x > 0}) => 15
> > > >
> > > > is there a better and simpler way to do it ?
> > > > thanks
> > >
> > > Did we have a solution with #inject already?
> >
> > array.inject(0){|i,e| if e>0; break i else i+1 end}
>
> array.inject(0){|i,e| break i if e>0; i+1 }
>

Using a regular expression ...

array.join =~ /[^0]/

The inject method is faster, though, because you do not have to create
a string. I'm assuming that the "array.index((array-[0])[0])" solution
suffers from the same problem -- creating another object under the
covers ...

$ ruby tmp.rb
                user system total real
inject 2.874000 0.000000 2.874000 ( 2.884000)
index 0.721000 0.000000 0.721000 ( 0.731000)
regexp 3.755000 0.000000 3.755000 ( 3.765000)

Wow! Looks like the "index" method wins hands down.

But mine is still shorter :wink:

TwP

Seems to be a general symptom of everything being optimised to run C
code - the C-like solutions win out.

m.

···

On 11/26/06, dblack@wobblini.net <dblack@wobblini.net> wrote:

This exchange relates to something I've been pondering for a while,
namely: is there always (or very, very often) an inverse relation
between elegance of code and efficiency? I don't mean to sound like
I'm singling out your example -- on the contrary, it seems that over
and over we see cases where a nice concise solution bombs out compared
to one that's longer, possibly less clear (I still can't read the
enum* stuff as quickly and confidently as I can read the regular
Enumerable stuff, though that may just be due to stupidity), but
faster.