Forum: Ruby Basic ruby looping question

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Marston A. (Guest)
on 2006-05-27 22:49
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.
Simen E. (Guest)
on 2006-05-27 23:01
(Received via mailing list)
You can use Array#select to get the values you want:

  for row in @large_row_array.select{ |row| row.element == "something" }
    something
  end
Joel VanderWerf (Guest)
on 2006-05-27 23:19
(Received via mailing list)
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)
Joel VanderWerf (Guest)
on 2006-05-27 23:32
(Received via mailing list)
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)
Daniel S. (Guest)
on 2006-05-28 00:11
(Received via mailing list)
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
Marston A. (Guest)
on 2006-05-28 00:18
Thanks everyone, I this was exactly what I needed.
Dave B. (Guest)
on 2006-05-28 08:19
(Received via mailing list)
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
This topic is locked and can not be replied to.