Эти два утверждения дают мне те же результаты:
[1,2,3,4].find_all { |x| x.even? }
[1,2,3,4].select{ |x| x.even? }
Является ли find_all
просто псевдонимом? Есть ли причина использовать один над другим?
Эти два утверждения дают мне те же результаты:
[1,2,3,4].find_all { |x| x.even? }
[1,2,3,4].select{ |x| x.even? }
Является ли find_all
просто псевдонимом? Есть ли причина использовать один над другим?
#find_all
и #select
очень похожи; разница очень тонкая. В большинстве случаев они эквивалентны. Это зависит от класса, реализующего его.
Enumerable#find_all
и Enumerable#select
работают по одному и тому же коду.
То же самое происходит для Array
и Range
, поскольку они используют реализацию Enumerable
.
В случае Hash
переопределяется #select
, чтобы возвращать Hash вместо массива, но #find_all
наследуется от Enumerable
a = [1, 2, 3, 4, 5, 6]
h = {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6}
a.select{|x| x.even?} # => [2, 4, 6]
a.find_all{|x| x.even?} # => [2, 4, 6]
h.select{|k,v| v.even?} # => {:b=>2, :d=>4, :f=>6}
h.find_all{|k,v| v.even?} # => [[:b, 2], [:d, 4], [:f, 6]]
Enumerable#find_all
Возвращает массив, содержащий все элементы перечисления, для которых данный блок возвращает истинное значение, что не относится к select
. Enumerable#select
возвращает Array
, если получатель, на который вы вызываете метод #select
, не имеет собственного метода #select
. В противном случае, на каком приемнике вы вызываете метод #select
, он будет возвращать аналогичный тип получателя после обработки состояния блока.
Как Hash#select
Возвращает новый хеш, состоящий из записей, для которых блок возвращает true
и Array#select
Возвращает новый массив, содержащий все элементы ary, для которых данный блок возвращает истинное значение. Теперь Range#select
вернет обратно Array
, поскольку класс Range
не имеет собственного метода экземпляра, называемого #select
. Вместо Enumerable
он вызывается Enumerable#select
.
rng = (1..4)
ary = [1,2]
hsh = {:a => 1}
rng.method(:select) # => #<Method: Range(Enumerable)#select>
hsh.method(:select) # => #<Method: Hash#select>
ary.method(:select) # => #<Method: Array#select>
Вот полная демонстрация с примером в пользу моего объяснения выше:
hsh = {:a => 2, :b => 3 }
ary = [1,2,3]
rng = (1..3)
# Look find_all always gives Array.
hsh.find_all{ true } # => [[:a, 2], [:b, 3]]
ary.find_all{ true } # => [1, 2, 3]
rng.find_all{ true } # => [1, 2, 3]
# Look select not giving Array always, explanation of why so is written
# above in my answer.
hsh.select{ true } # => {:a=>2, :b=>3}
ary.select{ true } # => [1, 2, 3]
rng.select{ true } # => [1, 2, 3]
Да, для массивов они возвращают одинаковые результаты. Для других вещей (например, хэши) они могут возвращать разные вещи.
В соответствии с документацией Enumerable для select и find_all оба метода указывают на тот же исходный код, и оба возвращают либо массив (если задан блок), либо Enumerator (если не задан блок).
В то время как класс Array реализует собственную версию select
(но позволяет Enumerable handle find_all
), они все равно выполняют одно и то же.