find index of first non zeo value in array

Discussion in 'Ruby' started by Josselin, Nov 26, 2006.

  1. Josselin

    Josselin Guest

    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
     
    Josselin, Nov 26, 2006
    #1
    1. Advertising

  2. Josselin

    Olivier Guest

    Le dimanche 26 novembre 2006 15:00, Josselin a =E9crit=A0:
    > with :
    > array =3D [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}) =3D> 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 =3D 0
    array.each{|v| break if not v.zero?; c +=3D 1}
    puts c # =3D> 15
     
    Olivier, Nov 26, 2006
    #2
    1. Advertising

  3. Josselin

    Guest

    ---2049402039-511287211-1164554586=:11709
    Content-Type: MULTIPART/MIXED; BOUNDARY="-2049402039-511287211-1164554586=:11709"

    This message is in MIME format. The first part should be readable text,
    while the remaining parts are likely unreadable without MIME-aware tools.

    ---2049402039-511287211-1164554586=:11709
    Content-Type: TEXT/PLAIN; charset=X-UNKNOWN; format=flowed
    Content-Transfer-Encoding: QUOTED-PRINTABLE

    Hi --

    On Sun, 26 Nov 2006, Olivier wrote:

    > Le dimanche 26 novembre 2006 15:00, Josselin a =E9crit=A0:
    >> with :
    >> array =3D [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}) =3D> 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 =3D 0
    > array.each{|v| break if not v.zero?; c +=3D 1}
    > puts c # =3D> 15


    Or:

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


    David

    --=20
    David A. Black |
    Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
    DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
    [1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
    [2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
    ---2049402039-511287211-1164554586=:11709--
    ---2049402039-511287211-1164554586=:11709--
     
    , Nov 26, 2006
    #3
  4. Josselin

    Guest

    , Nov 26, 2006
    #4
  5. On Nov 26, 2006, at 8:54 AM, Olivier wrote:

    > Le dimanche 26 novembre 2006 15:00, Josselin a =E9crit :
    >> with :
    >> array =3D [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}) =3D> 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 =3D 0
    > array.each{|v| break if not v.zero?; c +=3D 1}
    > puts c # =3D> 15


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

    >> require "enumerator"

    =3D> true
    >> array =3D [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, =20=


    0, 0,
    ?> 0, 0, 0, 0, 0, 0]
    =3D> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, =20=

    0, 0, 0, 0, 0]
    >> result =3D array.enum_with_index.find { |n, i| n.nonzero? }.last =20

    rescue nil
    =3D> 15
    >> array.slice!(15, 1)

    =3D> [21]
    >> array

    =3D> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =20=

    0, 0, 0]
    >> result =3D array.enum_with_index.find { |n, i| n.nonzero? }.last =20

    rescue nil
    =3D> nil

    James Edward Gray II=
     
    James Edward Gray II, Nov 26, 2006
    #5
  6. Josselin

    Park Heesob Guest

    Hi,

    >From: Josselin <>
    >Reply-To:
    >To: (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/
     
    Park Heesob, Nov 26, 2006
    #6
  7. Josselin

    Guest

    ---2049402039-1184309673-1164556388=:11991
    Content-Type: MULTIPART/MIXED; BOUNDARY="-2049402039-1184309673-1164556388=:11991"

    This message is in MIME format. The first part should be readable text,
    while the remaining parts are likely unreadable without MIME-aware tools.

    ---2049402039-1184309673-1164556388=:11991
    Content-Type: TEXT/PLAIN; charset=X-UNKNOWN; format=flowed
    Content-Transfer-Encoding: QUOTED-PRINTABLE

    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 =E9crit :
    >>>
    >>> array.index(array.detect {|x| x > 0}) =3D> 15

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

    >
    >>> result =3D 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

    --=20
    David A. Black |
    Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
    DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
    [1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
    [2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
    ---2049402039-1184309673-1164556388=:11991--
    ---2049402039-1184309673-1164556388=:11991--
     
    , Nov 26, 2006
    #7
  8. On Nov 26, 2006, at 9:53 AM, 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 =E9crit :
    >>>>
    >>>> array.index(array.detect {|x| x > 0}) =3D> 15
    >>> c =3D 0
    >>> array.each{|v| break if not v.zero?; c +=3D 1}
    >>> puts c # =3D> 15

    >>
    >>>> result =3D array.enum_with_index.find { |n, i| n.nonzero? }.last =20=


    >>>> 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 =20
    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 =20
    block for matching. That would solve this problem ideally. I can =20
    submit an RCR if people think it's worth it, but I'm pretty sure Matz =20=

    said it was OK last time it came up... (Correct me if I am wrong!)

    James Edward Gray II
     
    James Edward Gray II, Nov 26, 2006
    #8
  9. Josselin

    Guest

    ---2049402039-103646226-1164557367=:12154
    Content-Type: MULTIPART/MIXED; BOUNDARY="-2049402039-103646226-1164557367=:12154"

    This message is in MIME format. The first part should be readable text,
    while the remaining parts are likely unreadable without MIME-aware tools.

    ---2049402039-103646226-1164557367=:12154
    Content-Type: TEXT/PLAIN; charset=X-UNKNOWN; format=flowed
    Content-Transfer-Encoding: QUOTED-PRINTABLE

    Hi --

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

    > On Nov 26, 2006, at 9:53 AM, wrote:
    >
    >> On Mon, 27 Nov 2006, James Edward Gray II wrote:
    >>=20
    >>> On Nov 26, 2006, at 8:54 AM, Olivier wrote:
    >>>=20
    >>>> Le dimanche 26 novembre 2006 15:00, Josselin a =E9crit :
    >>>>>=20
    >>>>> array.index(array.detect {|x| x > 0}) =3D> 15
    >>>> c =3D 0
    >>>> array.each{|v| break if not v.zero?; c +=3D 1}
    >>>> puts c # =3D> 15
    >>>=20
    >>>>> result =3D array.enum_with_index.find { |n, i| n.nonzero? }.last resc=

    ue=20
    >>>>> nil

    >>=20
    >> 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 dete=

    ct()=20
    > 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=20
    > matching. That would solve this problem ideally. I can submit an RCR if=

    =20
    > people think it's worth it, but I'm pretty sure Matz said it was OK last =

    time=20
    > 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

    --=20
    David A. Black |
    Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
    DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
    [1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
    [2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
    ---2049402039-103646226-1164557367=:12154--
    ---2049402039-103646226-1164557367=:12154--
     
    , Nov 26, 2006
    #9
  10. 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
    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
     
    Devin Mullins, Nov 26, 2006
    #10
  11. Josselin

    Ross Bamford Guest

    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!)


    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

    --
    Ross Bamford -
     
    Ross Bamford, Nov 26, 2006
    #11
  12. On 11/26/06, <> 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.


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

    m.
     
    Martin DeMello, Nov 26, 2006
    #12
  13. 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? 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
     
    Robert Klemme, Nov 26, 2006
    #13
  14. 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
     
    Devin Mullins, Nov 26, 2006
    #14
  15. On Sunday 26 November 2006 21:22, Park Heesob wrote:
    > Hi,
    >
    > >From: Josselin <>
    > >Reply-To:
    > >To: (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/


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

    Regards,
    Pradeep
     
    Pradeep Jindal, Nov 27, 2006
    #15
  16. 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}
     
    William James, Nov 27, 2006
    #16
  17. 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 }
     
    William James, Nov 27, 2006
    #17
  18. Josselin

    Tim Pease Guest

    On 11/27/06, William James <> 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 ;)

    TwP
     
    Tim Pease, Nov 27, 2006
    #18
  19. Josselin

    Phrogz Guest

    Devin Mullins wrote:
    > 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
    > end
    > nil
    > end
    > end


    Hrm, I assumed that using #each_with_index would be speedier, since
    there would be no Ruby call to the #[] method of the array for each
    iteration. Instead, it's much slower:

    class Array
    alias orig_index index

    def index1(*args)
    return orig_index(*args) unless block_given?
    (0...length).each do |i|
    return i if yield self
    end
    nil
    end

    def index2( *args )
    return orig_index(*args) unless block_given?
    each_with_index{ |value,index| return index if yield value }
    nil
    end
    end

    require 'benchmark'
    N = 1000
    a = (1..1000).to_a
    Benchmark.bmbm{ |x|
    x.report( '0...length' ){
    N.times{ |i| a.index1{ |v| v==i } }
    }

    x.report( 'each_with_i' ){
    N.times{ |i| a.index2{ |v| v==i } }
    }
    }

    #=> Rehearsal -----------------------------------------------
    #=> 0...length 2.060000 0.030000 2.090000 ( 2.333379)
    #=> each_with_i 3.340000 0.050000 3.390000 ( 3.727040)
    #=> -------------------------------------- total: 5.480000sec
    #=>
    #=> user system total real
    #=> 0...length 2.060000 0.020000 2.080000 ( 2.286168)
    #=> each_with_i 3.350000 0.040000 3.390000 ( 3.716824)
     
    Phrogz, Nov 28, 2006
    #19
  20. Josselin

    x1 Guest

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

    On 11/26/06, 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
    >
    > joss
    >
    >
    >
     
    x1, Nov 28, 2006
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. drs

    ZEO and COM

    drs, Jul 11, 2003, in forum: Python
    Replies:
    0
    Views:
    386
  2. drs

    More ZEO/ZODB issues

    drs, Jul 12, 2003, in forum: Python
    Replies:
    0
    Views:
    333
  3. Almad

    IndexedCatalog and ZEO

    Almad, Mar 6, 2005, in forum: Python
    Replies:
    4
    Views:
    391
    Almad
    Mar 7, 2005
  4. Paul Boots
    Replies:
    0
    Views:
    344
    Paul Boots
    Jun 21, 2005
  5. Shawn W_
    Replies:
    5
    Views:
    302
    Aldric Giacomoni
    Sep 16, 2009
Loading...

Share This Page