views:

52

answers:

1

I play around with arrays and hashes quite a lot in ruby and end up with some code that looks like this:

sum = two_dimensional_array.select{|i|
  i.collect{|j|
    j.to_i
  }.sum > 5
}.collect{|i|
  i.collect{|j|
    j ** 2
  }.average
}.sum

(Let's all pretend that the above code sample makes sense now...)

The problem is that even though TextMate (my editor of choice) picks up simple {...} or do...end blocks quite easily, it can't figure out (which is understandable since even I can't find a "correct" way to fold the above) where the above blocks start and end to fold them.

How would you fold the above code sample?

PS: considering that it could have 2 levels of folding, I only care about the outer consecutive ones (the blocks with the i)

+1  A: 

To be honest, something that convoluted is probably confusing TextMate as much as anyone else who has to maintain it, and that includes you in the future.

Whenever you see something that rolls up into a single value, it's a good case for using Enumerable#inject.

sum = two_dimensional_array.inject(0) do |sum, row|
  # Convert row to Fixnum equivalent
  row_i = row.collect { |i| i.to_i }

  if (row_i.sum > 5)
    sum += row_i.collect { |i| i ** 2 }.average
  end

  sum # Carry through to next inject call
end

What's odd in your example is you're using select to return the full array, allegedly converted using to_i, but in fact Enumerable#select does no such thing, and instead rejects any for which the function returns nil. I'm presuming that's none of your values.

Also depending on how your .average method is implemented, you may want to seed the inject call with 0.0 instead of 0 to use a floating-point value.

tadman
The code I posted is just something I wrote down without really looking into it, I just wanted to give it the approximate look of much of the code I write (/me turns select -> collect).I will look into inject and whether it helps me simplify things.
vrinek