Selecting indices from an array

For an array a, I would like to know all the indices i where a[i]
fulfils
some condition. My solution (which works) looks like this:

a=%w(Deutschlandsberg Stainz Preding Eibiswald)
(0...a.size).select {|i| a[i]=~/g$/} # ==> [0,2]

What I don't like with this solution is that inside the code block
supplied to select, I also have to access the array variable a which
is declared outside. I would prefer having my code block "self
contained", using only the variables passed as parameter.

Is there in Ruby a function similar select, where I also get the array
element passed through, kind of:

   a.select_index {|index,value| value?~/g$/}

or do I have to write my own here? I don't want to reinvent the
wheel....

Ronald

···

--
Ronald Fischer <ronald.fischer@venyon.com>
Phone: +49-89-452133-162

Alle giovedì 23 agosto 2007, Ronald Fischer ha scritto:

For an array a, I would like to know all the indices i where a[i]
fulfils
some condition. My solution (which works) looks like this:

a=%w(Deutschlandsberg Stainz Preding Eibiswald)
(0...a.size).select {|i| a[i]=~/g$/} # ==> [0,2]

What I don't like with this solution is that inside the code block
supplied to select, I also have to access the array variable a which
is declared outside. I would prefer having my code block "self
contained", using only the variables passed as parameter.

Is there in Ruby a function similar select, where I also get the array
element passed through, kind of:

   a.select_index {|index,value| value?~/g$/}

or do I have to write my own here? I don't want to reinvent the
wheel....

Ronald

You can do this:

require 'enumerator'
a.enum_for(:each_with_index).select{|value, index value.match /g$/
  }.map{|value, index| index}

enum_for returns an object of class Enumerable::Enumerator whose each method
calls the argument of enum_for, in this case each_with_index. select then
returns an array of pairs [value, index], where value are matching values and
index their index in a. To extract only the indices, map is called on this
array. The downside of this approach is that it needs two iterations: one on
the original array and one on the array of matching results. If this is a
problem, you can use this:

a.enum_for(:each_with_index).inject(){|res, i|
  i[0].match( /g$/) ? res << i[1] : res
}

or

matching =
a.enum_for(:each_with_index).each{|value, index|
  matching << index if value.match(/g$/)
}

I hope this helps

Stefano

If this is a
problem, you can use this:

a.enum_for(:each_with_index).inject(){|res, i|
  i[0].match( /g$/) ? res << i[1] : res
}

This is an idea I like! Thanks a lot!

Ronald

···

--
Ronald Fischer <ronald.fischer@venyon.com>
Phone: +49-89-452133-162

And you can make it even easier to read:

  a.enum_for(:each_with_index).inject(){|res, (elem, idx)|
    elem.match( /g$/) ? res << idx : res
  }

Regards,
Pit

···

2007/8/23, Ronald Fischer <ronald.fischer@venyon.com>:

>
> a.enum_for(:each_with_index).inject(){|res, i|
> i[0].match( /g$/) ? res << i[1] : res
> }

This is an idea I like! Thanks a lot!

accum =
a.each_with_index{|s,i| accum << i if s =~ /g$/ }

···

On Aug 23, 8:08 am, "Ronald Fischer" <ronald.fisc...@venyon.com> wrote:

> If this is a
> problem, you can use this:

> a.enum_for(:each_with_index).inject(){|res, i|
> i[0].match( /g$/) ? res << i[1] : res
> }

This is an idea I like! Thanks a lot!

Ronald
--
Ronald Fischer <ronald.fisc...@venyon.com>
Phone: +49-89-452133-162

Posted by Ronald Fischer (Guest) on 23.08.2007 12:59

...
Is there in Ruby a function similar select, where I also get the array element passed through, kind of:

a.select_index {|index,value| value?~/g$/}

or do I have to write my own here? I don't want to reinvent the wheel....

Ronald

How about:

module Enumerable
  def select_index
    index = -1
    (block_given? && self.class == Range || self.class == Array) ?
collect { |x| index += 1; yield(x,index) }.compact : self
  end
end

p ("a".."n").select_index { |x,i| i if x =~ /[c-g]/ }
=> [2, 3, 4, 5, 6]

Cheers,

j.k.

···

--
Posted via http://www.ruby-forum.com/\.

And to generalize further, let's abstract the test (it shouldn't matter
what the test is, just as it shouldn't matter what the array is):

#specific part
a=%w(Deutschlandsberg Stainz Preding Eibiswald)
test = Proc.new {|s| s=~/g$/}

#general part
result =
a.each_with_index {|ss,ix| result << ix if test.call(ss)}

Or, even more general (because the names stop mattering):

def indices_matching_test(a)
  result =
  a.each_with_index {|ss,ix| result << ix if yield ss}
  result
end

#and here's how to use it:
a=%w(Deutschlandsberg Stainz Preding Eibiswald)
test = Proc.new {|s| s=~/g$/}
puts indices_matching_test(a, &test)

m.

···

William James <w_a_x_man@yahoo.com> wrote:

On Aug 23, 8:08 am, "Ronald Fischer" <ronald.fisc...@venyon.com> > wrote:
> > If this is a
> > problem, you can use this:
>
> > a.enum_for(:each_with_index).inject(){|res, i|
> > i[0].match( /g$/) ? res << i[1] : res
> > }
>
> This is an idea I like! Thanks a lot!
>
> Ronald
> --
> Ronald Fischer <ronald.fisc...@venyon.com>
> Phone: +49-89-452133-162

accum =
a.each_with_index{|s,i| accum << i if s =~ /g$/ }

--
matt neuburg, phd = matt@tidbits.com, Matt Neuburg’s Home Page
Tiger - http://www.takecontrolbooks.com/tiger-customizing.html
AppleScript - http://www.amazon.com/gp/product/0596102119
Read TidBITS! It's free and smart. http://www.tidbits.com

> > > If this is a
> > > problem, you can use this:

> > > a.enum_for(:each_with_index).inject(){|res, i|
> > > i[0].match( /g$/) ? res << i[1] : res
> > > }

> > This is an idea I like! Thanks a lot!

> > Ronald
> > --
> > Ronald Fischer <ronald.fisc...@venyon.com>
> > Phone: +49-89-452133-162

> accum =
> a.each_with_index{|s,i| accum << i if s =~ /g$/ }

And to generalize further, let's abstract the test (it shouldn't matter
what the test is, just as it shouldn't matter what the array is):

#specific part
a=%w(Deutschlandsberg Stainz Preding Eibiswald)
test = Proc.new {|s| s=~/g$/}

Why so prolix?

test = proc{|s| s =~ /g$/}

#general part
result =
a.each_with_index {|ss,ix| result << ix if test.call(ss)}

Or, even more general (because the names stop mattering):

def indices_matching_test(a)
  result =
  a.each_with_index {|ss,ix| result << ix if yield ss}
  result
end

#and here's how to use it:
a=%w(Deutschlandsberg Stainz Preding Eibiswald)
test = Proc.new {|s| s=~/g$/}
puts indices_matching_test(a, &test)

Even better:
p indices_matching_test(a){|s| s =~ /g$/}

···

On Aug 24, 1:44 pm, m...@tidbits.com (matt neuburg) wrote:

William James <w_a_x_...@yahoo.com> wrote:
> On Aug 23, 8:08 am, "Ronald Fischer" <ronald.fisc...@venyon.com> > > wrote: