Безопасное добавление метода sum в класс Array

Я часто суммирую массивы в своем коде, поэтому я думаю о том, чтобы обезьяна исправить класс Array, чтобы включить метод суммы (который суммирует все элементы в массиве):

class Array
  def sum
    self.inject{ |s, t| s + t }
  end
end

Однако я никогда раньше ничего не исправлял в общем коде и сомневаюсь, что это «безопасный» способ (например, может быть, кто-то уже определил sum метод в Array).

Итак, как лучше всего иметь возможность суммировать массивы в коде, который я пишу, без необходимости писать arr.inject{ |s, t| s + t } каждый раз? Есть ли безопасный способ обезьяньего патча? Могу я как-нибудь использовать модуль? Или мне просто написать где-нибудь вспомогательный метод, который принимает массив и возвращает сумму (т.е. def sum_array(arr); return arr.inject{ |s, t| s + t }; end)? (Или есть какой-то совершенно другой подход?)


person grautur    schedule 22.07.2011    source источник
comment
Я лично обезьяна-патч (хотя я обезьяна-патч в Enumerable#sum, а не только Array#sum), но, конечно, любой обезьяний-патч небезопасен. Без чего-то вроде remix, несомненно, самым безопасным вариантом будет вспомогательный метод.   -  person Phrogz    schedule 23.07.2011
comment
self - это получатель по умолчанию в Ruby, поэтому вы можете не использовать его. Ваш блок эквивалентен &:+, поэтому вы можете также написать метод как inject(&:+). inject даже принимает аргумент символа и выполняет преобразование блока за вас, так что вы также можете избавиться от &. Также обратите внимание, что вы на самом деле не зависите от того факта, что self является Array, только то, что у него есть метод inject, поэтому вы можете поднять его до Enumerable и получить module Enumerable; def sum; reduce(:+) end end.   -  person Jörg W Mittag    schedule 23.07.2011
comment
возможно, кто-то еще уже определил метод sum в Array - действительно, он есть в _ 3_. Какой BTW более гибкий, чем ваш, и лучше справляется с угловым случаем пустой коллекции.   -  person Jörg W Mittag    schedule 23.07.2011


Ответы (2)


inject на самом деле может принимать символьный аргумент, поэтому все, что вам действительно нужно написать, это arr.inject(:+), что, как мне кажется, не требует более короткой формы.

http://www.ruby-doc.org/core/classes/Enumerable.html#M001494

person Michael Kohl    schedule 22.07.2011
comment
Я предпочитаю использовать синоним arr.reduce(:+), потому что считаю сокращение более интуитивным для fxn. Определенно лучший способ справиться с этим любым именем. - person Ryanmt; 23.07.2011
comment
Smalltalk использует inject:into: и collect:, поэтому reduce и map имеют соответствующие синонимы в Ruby :-) - person Michael Kohl; 23.07.2011
comment
Что ж, inject: aValue into: aBlock имеет смысл, когда вы читаете это вслух, inject(a_value, &a_block) читается не так хорошо. На самом деле inject в Ruby эквивалентен двум различным функциям, обычно называемым fold (для формы с двумя аргументами inject) и reduce или fold1 (для формы с одним аргументом). В данном конкретном случае он используется как reduce, и я предпочитаю записывать его так, когда он используется таким образом, и inject в противном случае. - person Jörg W Mittag; 23.07.2011
comment
@ Jörg: хотя это очевидно верно, это не меняет того факта, что псевдонимы существуют для старых Smalltalker-ов. Лично мне просто лень переключаться между reduce и inject в зависимости от контекста, поэтому я всегда использую последний. Я никогда не использую collect, но считаю, что map просто имеет больше смысла. В общем, я бы сказал, дело предпочтений. - person Michael Kohl; 23.07.2011

Вы всегда можете создать подкласс массива и определить его там. Скажем, если бы у вас было AdderArray < Array, вы могли бы найти такую ​​сумму:

AdderArray.new(a1).sum

Или вы можете просто определить вспомогательную библиотеку:

ArrayHelper.sum(a1)

Что делать, действительно зависит от вас. Я даже не вижу проблемы с патчем обезьяны (каков шанс, что кто-то создаст метод массива с именем sum, который не суммирует?). Даже если конфликт все-таки возникнет, вы всегда можете переименовать его в sum_members.

person Karl    schedule 22.07.2011