Basic ruby looping question


#1

I’m trying to do something regarding looping through an array, but only
with elements I need. I’m not sure exactly how to go about it to make it
the most efficient. Is there basically a way to do something like:

for row in @large_row_array WHERE row.element == “something”
… some some stuff
end

What would be the best way to accomplish the above? Would I use perhaps
some nested loops? Thanks for any help, I’m just getting started with
Ruby along with more indepth programming in general and I’m loving it.


#2

You can use Array#select to get the values you want:

for row in @large_row_array.select{ |row| row.element == “something” }
something
end


#3

Marston A. wrote:

Ruby along with more indepth programming in general and I’m loving it.
I’m not sure if it’s always more efficient, but you can use grep in some
cases:

irb(main):003:0> ENV.keys.grep(/ruby/i) {|key| p key}
“RUBYOPT”
“RUBYLIB”

This is more or less the same as

irb(main):004:0> ENV.keys.each {|key| if /ruby/i === key then p key end}
“RUBYOPT”
“RUBYLIB”

(The return values are quite different though.)

So as long as you are working with tests that can be expressed using
#===, you can use #grep. It’s compact, and at least sometimes more
efficient.

require ‘benchmark’

a = (0…1_000_000).map {|i| i.to_s}

def foo s
end

Benchmark.bmbm do |b|
b.report(“grep”) do
a.grep(/^10*$/) {|s| foo s}
end

b.report(“each-if”) do
a.each {|s| if /^10*$/ === s then foo s end }
end

b.report(“select-each”) do
a.select {|s| /^10*$/ === s}.each {|s| foo s}
end
end

END

Rehearsal -----------------------------------------------
grep 0.490000 0.000000 0.490000 ( 0.492667)
each-if 0.640000 0.000000 0.640000 ( 0.638102)
select-each 0.760000 0.000000 0.760000 ( 0.758676)
-------------------------------------- total: 1.890000sec

              user     system      total        real

grep 0.490000 0.000000 0.490000 ( 0.487539)
each-if 0.640000 0.000000 0.640000 ( 0.639301)
select-each 0.620000 0.010000 0.630000 ( 0.621152)


#4

Marston A. wrote:

for row in @large_row_array WHERE row.element == “something”
… some some stuff
end

@array.select{|row| row.element == “something”}.each do |row|
… some stuff
end

Cheers,
Daniel


#5

Joel VanderWerf wrote:

Marston A. wrote:

for row in @large_row_array WHERE row.element == “something”
… some some stuff
end

So as long as you are working with tests that can be expressed using
#===, you can use #grep.

In your case, grep may not be so useful after all. You would have to
define an object whose #=== method performs the row.element ==
“something” test.

require ‘benchmark’

tester = Object.new
def tester.===(row)
row.element == 987654
end

class Row
attr_accessor :element
end

rows = (0…1_000_000).map {|i| r = Row.new; r.element = i; r}

Benchmark.bmbm do |b|
b.report(“grep”) do
rows.grep(tester) {|row|}
end

b.report(“each-if”) do
rows.each {|row| if row.element == 987654 then nil end }
end

b.report(“select-each”) do
rows.select {|row| row.element == 987654}.each {|row|}
end
end

END

Rehearsal -----------------------------------------------
grep 0.720000 0.000000 0.720000 ( 0.725553)
each-if 0.590000 0.000000 0.590000 ( 0.587160)
select-each 0.770000 0.000000 0.770000 ( 0.768704)
-------------------------------------- total: 2.080000sec

              user     system      total        real

grep 0.730000 0.000000 0.730000 ( 0.735809)
each-if 0.590000 0.000000 0.590000 ( 0.587350)
select-each 0.570000 0.000000 0.570000 ( 0.564276)


#6

Thanks everyone, I this was exactly what I needed.


#7

Marston A. wrote:

I’m trying to do something regarding looping through an array, but only
with elements I need. I’m not sure exactly how to go about it to make it
the most efficient. Is there basically a way to do something like:

for row in @large_row_array WHERE row.element == “something”
… some some stuff
end

You can use array.select as the others have mentioned, or you can use
next like this:

for row in @large_row_array
next unless row.element == “something”
… some some stuff
end

That might be a bit quicker over large data sets, too – select will
loop through your data before the for loop.

Cheers,
Dave