2

I have a loop that looks like this

def slow_loop(array)
 array.each_with_index do |item, i|
   next_item = array[i+1]
   if next_item && item.attribute == next_item.attribute
     do_something_with(next_item)
   end
 end
end

aside from changing the way do_something_with is called, how can i make this perform better?

thx,

-C

p.s.

Since it appears that this is an 'O(n)' operation, there is apparently no performance to be gained here, so the answer i chose is one that uses a ruby method that already encapsulates this operation. thanks for your help everybody

7
  • Perhaps you should let us know how many elements you have and any sort of benchmarking figures you came up with? This SHOULD be a O(n) operation. Commented Apr 27, 2009 at 20:20
  • forgive me if this sounds dumb, but, what's an O(n) operation? Commented Apr 27, 2009 at 20:22
  • Basically, the time of the operation O is a directly related to the number of elements n Commented Apr 27, 2009 at 20:24
  • en.wikipedia.org/wiki/Big_O_notation Commented Apr 27, 2009 at 20:25
  • 1
    It's worth noting that just because it's an O(n) algorithm doesn't mean that you can't get any more performance out of it. There are lots of times when the best possible algorithm is O(n) but you can still shoot yourself in the foot with a pathological O(n) algorithm. e.g., iterating over a matrix column-major when it's stored row-major. In your case, it's a really simple algorithm, and not much room for improvement. But keep in mind that even though you should examine the complexity of your algorithm first, getting the best performance is often about large constant factors. Commented Apr 27, 2009 at 20:54

3 Answers 3

6

As others have mentioned you're not going to improve the performance much, but you could do this more cleanly like so:

array.each_cons(2) do |a, b|
  do_something_with(b) if a == b
end
Sign up to request clarification or add additional context in comments.

5 Comments

should next_item be 'b' here?
Interesting - I hadn't seen each_cons before.
@Sara Mei: It's in enumerable... there is also each_slice, which is the non-sliding window version.
although it sucks my performance loss is not coming from the loop, this is a pretty nice way of doing this.. thx :)
Note that each_cons and each_slice are only in native Ruby as of 1.9, although they do exist in the Enumerable extensions implemented in Rails from (at least, possibly earlier) 2.1.2 onwards
2

The performance of do_something_with is the main factor. Anything else would be micro-optimisation.

This should be O(n), you could work out a way to avoid the final check, but that's not going to be that costly in the grand scheme of things.

1 Comment

if that's the case, I guess my only other question would be, is there a ruby method that already encapsulates this type of procedure?
0

I tend to agree with Garry on the optimization potential, but it can certainly be written more simply.

prev_attr = nil
my_array.each |item|
  do_something_with(item) if prev_attr and prev_attr == item.attribute
  prev_attr = item.attribute
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.