Сворачивание кода при последовательном сборе / выборе / отклонении / каждом
Вопрос
Я довольно много играю с массивами и хэшами в ruby и в итоге получаю некоторый код, который выглядит примерно так:
sum = two_dimensional_array.select{|i|
i.collect{|j|
j.to_i
}.sum > 5
}.collect{|i|
i.collect{|j|
j ** 2
}.average
}.sum
(Давайте все притворимся, что приведенный выше пример кода теперь имеет смысл ...)
Проблема в том, что даже несмотря на то, что TextMate (мой любимый редактор) подбирает простые {...}
или do...end
блоки довольно легко, он не может определить (что понятно, поскольку даже я не могу найти "правильный" способ сложить вышеуказанное), где вышеупомянутые блоки начинаются и заканчиваются, чтобы их сложить.
Как бы вы сложили приведенный выше пример кода?
PS:учитывая, что у него может быть 2 уровня складывания, меня интересуют только внешние последовательные блоки (блоки с i).
Решение
Честно говоря, что-то такое запутанное, вероятно, сбивает TextMate с толку не меньше, чем любого другого, кому приходится его поддерживать, и это включает вас в будущем.
Всякий раз, когда вы видите что-то, что сводится к одному значению, это хороший пример для использования 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
Что странно в вашем примере, так это то, что вы используете select для возврата полного массива, предположительно преобразованного с помощью to_i , но на самом деле Enumerable#select не делает ничего подобного, а вместо этого отклоняет любой, для которого функция возвращает nil .Я предполагаю, что это не входит в число ваших ценностей.
Также в зависимости от того, как реализован ваш метод .average, вы можете захотеть заполнить вызов inject значением 0.0 вместо 0, чтобы использовать значение с плавающей запятой.