2014-02-05 3 views
7

У меня есть INJECT позвонитьВводят оператор двойной амперсанд

[2,4,6].inject(true) { |res, val| res && val % 2 == 0 } 

и хотите отправить && оператору впрыснуть как в inject(0, :+). Как я могу это сделать?

+0

Инъекция в _boolean_ значение звучит странно для меня. Я бы использовал smth, как '.each {| e | break false if ...} '. – mudasobwa

ответ

10

Вы не можете, потому что && и ||, в отличие от других операторов, не syntacic сахара методов (т.е. не существует метод, называемый && или ||), так что вы не можете ссылаться на них, используя символ.

Однако вы можете избежать использования inject вычислить логическую конъюнкцию или дизъюнкцию массив булевых значений, заменив его all? или any? соответственно, потому что для любого массива выполняются следующие условия:

ary.inject(true) { |res, b| res && b } == ary.all? 
ary.inject(false) { |res, b| res || b } == ary.any? 

Итак, например, код размещен можно переписать в виде:

[2,4,6].map(&:even?).all? 
# => true 

Update: очевидно, мой последний пример не правильный способ выразить это вычисление, ответ falsetru является гораздо быстрее:

require 'fruity' 

compare(
    -> { (0..1000).map(&:even?).all? }, 
    -> { (0..1000).all?(&:even?) } 
) 
Running each test 1024 times. Test will take about 2 seconds. 
Code 2 is faster than Code 1 by 111x ± 10.0 
+0

Итак, ваши предположения для начального значения, переданного для инъекции, несогласны с тем, что я хотел выполнить: [] .reduce (: any_method) == nil, поэтому я надеялся на ary.reduce (: &&), чтобы проверить наличие и все истинные значения. Думаю, вы пытаетесь выжать слишком много из синтаксического сахара рубина. ary.present? && ary.all? (просто надеялся не хранить временную переменную) –

8

Как об использовании Enumerable#all?

[2,4,6].all? &:even? 
# => true 
[2,4,6,5].all? &:even? 
# => false 

Если вы хотите использовать inject, вам нужно определить метод экземпляра.

class Object 
    def is_even(val) 
    self && val % 2 == 0 
    end 
end 

[2,4,6].inject(true, :is_even) # => true 
[1,2,4,6,5].inject(true, :is_even) # => false 
+0

Извините, пример мог ввести вас в заблуждение, я не хочу проверять четные числа в инъекции, я хочу, чтобы оператор && вызывал многократно на предикат, чтобы дать мне логический результат. – zacsek

+0

@zacsek, я обновил ответ. Проверьте это. – falsetru

3

'& &' это не метод, следовательно, вы не можете вводить его. Однако вы можете ввести метод &.

[2,4,6,5].map(&:even?).inject(true, :&) 

Что будет делать то же

Примечание: Это, однако, не должно быть сделано, поскольку это крайне рискованно и может привести к неожиданным последствиям (при запуске по сбору, содержащей, по меньшей мере, один не-логическое значение (истина, false, ноль). Вы всегда должны использовать any? или all?.

+5

Просто, чтобы уточнить, хотя вы уже знаете это: & и && эквивалентны здесь только потому, что операнды являются логическими. – tokland

0

inject(0, :+) бы добавить все элементы массива, независимо от того, что содержание элементов (нечетные, четные, и т.д).

Если вы хотите inject(true, &:&&) (я знаю, что это не работает), ваш массив должен быть массив логических значений для вашего вопроса, чтобы понять, что будет такой же, как: [true, false].all?

важно: вы не можете передать оба блока arg и фактический блок, что означает, что вы не можете проверить, равно ли даже вставлять & & в то же время.

Если вы настаиваете, попробуйте это:

[2,4,6].inject(true, & lambda { |x,y| x && y }) 
=> 6 

Это эквивалент того, что вы просите (что я до сих пор не полностью понимаю)

Смежные вопросы