[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Selecting indices from an array

Ronald Fischer

8/23/2007 10:58:00 AM

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

7 Answers

Stefano Crocco

8/23/2007 11:11:00 AM

0

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

Ronald Fischer

8/23/2007 1:09:00 PM

0

> 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

Pit Capitain

8/24/2007 6:23:00 AM

0

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!

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

Jimmy Kofler

8/24/2007 11:56:00 AM

0

> 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-....

William James

8/24/2007 3:46:00 PM

0

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

8/24/2007 6:45:00 PM

0

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$/ }

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.

--
matt neuburg, phd = matt@tidbits.com, http://www.tidbits...
Tiger - http://www.takecontrolbooks.com/tiger-custom...
AppleScript - http://www.amazon.com/gp/product/...
Read TidBITS! It's free and smart. http://www.t...

William James

8/24/2007 8:16:00 PM

0

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:
> > > > 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$/}