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.
Df0a460118ef876e45b13b8c1a471454?d=identicon&s=25 Marston A. (marstoni)
on 2006-05-27 20: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.
F2d901ea9430646c6dd35a629bb3f119?d=identicon&s=25 Simen Edvardsen (Guest)
on 2006-05-27 21: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
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2006-05-27 21: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)
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2006-05-27 21: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)
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-05-27 22: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
Df0a460118ef876e45b13b8c1a471454?d=identicon&s=25 Marston A. (marstoni)
on 2006-05-27 22:18
Thanks everyone, I this was exactly what I needed.
0b561a629b87f0bbf71b45ee5a48febb?d=identicon&s=25 Dave Burt (Guest)
on 2006-05-28 06: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.