2010-03-01 5 views
7

Предположим, что у меня есть массив значений [a, b, c, d, ...] и функция f (x, ...), которая возвращает true или false.Лучший функциональный подход к И через список

[1,2,3,4].map {|x| f(x)} => [true true false true] 

Во-первых, что является лучшим способом свернуть результирующий список в истинное или ложное значение (через AND)? Есть функция, которая позволила бы мне на карту:

[true true false true] 

к:

((true && true) && false) && true 

с использованием кумулятивного парного применения бинарного & & оператора?

В этом случае стоимость оценки функции является финансовой, поэтому хотелось бы использовать lisp-style "и" для последовательного вычисления аргументов (приложений-функций), пока один из них не будет ложным. Определено, что можно сделать:

!![1,2,3,4].each {|x| break false if !f(x) } 

Какая уродливость. Надеясь, что есть более элегантный способ сделать это. Я знаю, что я мог бы добавить новое понимание в Array, но надеясь, что есть что-то встроенное, что делает это лучше. Спасибо

ответ

12

Вы ищете Enumerable#all?, который возвращает true, если все вызовы его блока являются правдивыми. Существует также Enumerable#any?, которая возвращает истину, если какой-либо из заклятий его блока являются truthy:

#!/usr/bin/ruby1.8 

def even(n) 
    n % 2 == 0 
end 

p [1, 2, 3, 4].all? { |i| even(i) } # => false 
p [2, 4, 6, 8].all? { |i| even(i) } # => true 
p [1, 2, 3, 4].any? { |i| even(i) } # => true 
p [1, 3, 5, 7].any? { |i| even(i) } # => false 

any? короткозамыкатели curcuits: первое truthy значение заставляет его вернуться верно. Так происходит all? короткое замыкание: первое значение ложности заставляет его возвращать false.

+0

Извините за nitpicking, но 'Fixnum' уже имеет методы' even? 'И' odd? '...;) –

+0

@Mladen Jablanovic, Хорошая точка. В этом примере мне нужна пользовательская функция. –

1

Как насчет: [true, true, false, true].all?

Это возвращает истину, если массив не содержит ничего, что соответствует значению ЛОЖЬ или ноль.

3

Вы можете попробовать складывая свой массив:

[true,true,false,true].inject(:&) #=> false (AND-ed) 
[true,true,false,true].inject(:|) #=> true (OR-ed) 
[1,2,3,4].inject(:+)    #=> 10 (summed) 
[1,2,3,4].inject(:*)    #=> 24 (multiplied) 

Вы получаете ключ. Возвращаясь к вашему примеру:

[1,2,3,4].map {|x| f(x) }.inject(:&) 

Однако это не будет короткого замыкания - вы, вероятно, лучше смотреть в «какие-то?» или "все?" кроме вашего "f()" имеет побочные эффекты (например, изменение постоянной памяти).

+0

Спасибо, это отвечает на первый вопрос! Ответ Уэйн второй. –

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