Selecting indices from an array

R

Ronald Fischer

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

a=3D%w(Deutschlandsberg Stainz Preding Eibiswald)
(0...a.size).select {|i| a=3D~/g$/} # =3D=3D> [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=20
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
--=20
Ronald Fischer <[email protected]>
Phone: +49-89-452133-162
 
S

Stefano Crocco

Alle gioved=EC 23 agosto 2007, Ronald Fischer ha scritto:
For an array a, I would like to know all the indices i where a
fulfils
some condition. My solution (which works) looks like this:

a=3D%w(Deutschlandsberg Stainz Preding Eibiswald)
(0...a.size).select {|i| a=3D~/g$/} # =3D=3D> [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 metho=
d=20
calls the argument of enum_for, in this case each_with_index. select then=20
returns an array of pairs [value, index], where value are matching values a=
nd=20
index their index in a. To extract only the indices, map is called on this=
=20
array. The downside of this approach is that it needs two iterations: one o=
n=20
the original array and one on the array of matching results. If this is a=20
problem, you can use this:

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

or=20

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

I hope this helps

Stefano
 
R

Ronald Fischer

If this is a=20
problem, you can use this:
=20
a.enum_for:)each_with_index).inject([]){|res, i|=20
i[0].match( /g$/) ? res << i[1] : res
}

This is an idea I like! Thanks a lot!

Ronald
--=20
Ronald Fischer <[email protected]>
Phone: +49-89-452133-162
 
P

Pit Capitain

2007/8/23 said:
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
 
J

Jimmy Kofler

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

matt neuburg

William James said:
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

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

William James

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

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,123
Latest member
Layne6498
Top