Лучший функциональный подход к И по всему списку - PullRequest
7 голосов
/ 01 марта 2010

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

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

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

[true true false true]

до:

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

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

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

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

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

Ответы [ 3 ]

12 голосов
/ 01 марта 2010

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

#!/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? short-curcuits: первое истинное значение заставляет его возвращать true. Так же, как и all? короткое замыкание: первое ложное значение заставляет его возвращать ложь.

3 голосов
/ 01 марта 2010

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

[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 ()" есть побочные эффекты (например, изменение постоянного хранилища).

1 голос
/ 01 марта 2010

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

Это вернет true, если массив не содержит ничего, что оценивается как false или nil.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...