2009-09-28 20 views
7

Parece una pregunta ridículamente simple, pero ¿cuál es la forma más corta/más idiomática de reescribir esto en Ruby?¿Cuál es la forma más corta/más idiomática de determinar si una variable es cualquiera de una lista de valores?

if variable == :a or variable == :b or variable == :c or variable == :d # etc. 

vi esta solución:

if [:a, :b, :c, :d].include? variable 

pero esto no siempre es funcionalmente equivalente - Creo Array#include? se ve en realidad para ver si el objeto variable está contenida en la lista; no tiene en cuenta que el objeto puede implementar su propia prueba de igualdad con def ==(other).

Según lo observado por los comentaristas útiles a continuación, esa explicación no es correcta. include? usa == pero usa el método == de los elementos en la matriz. En mi ejemplo, son los símbolos, en lugar del método == de la variable. Eso explica por qué no es equivalente a mi primer ejemplo de código.

(Tomemos, por ejemplo, Rails Mime::Type aplicación: request.format == :html puede devolver cierto, pero [:html].include?(request.format) volverá falso, como request.format es una instancia de Mime :: Tipo, no un símbolo.)

los mejores que he hasta ahora es:

if [:a, :b, :c, :d].select {|f| variable == f}.any? 

pero me parece un poco engorroso. ¿Alguien tiene mejores sugerencias?

+0

creo que el "Cualquier" sintaxis parece bastante limpio. Pero, soy C# y tt solo refleja cómo se ve LINQ, así que estoy predispuesto. –

+0

La documentación dice: Array # include? Devuelve verdadero si el objeto dado está presente en uno mismo (es decir, si cualquier objeto == un Objeto), de lo contrario es falso. – khelll

+0

Me pregunto si la implementación de un método isOneOf? (Array) en la clase Object no se considera una buena práctica en ruby, es decir, meterse con las clases base (obviamente, no tengo experiencia con ruby) ... de todos modos, sería estar bien si alguien puede publicar tal método .... – opensas

Respuesta

15

En realidad, #include?hace usa ==. El problema surge del hecho de que si lo hace

[:a].include? foo 

comprueba :a == foo, no foo == :a. Es decir, usa el método == definido en los objetos en la matriz, no la variable. Por lo tanto, puede usarlo siempre que se asegure de que los objetos en la matriz tengan un método apropiado ==.

En los casos en que no va a funcionar, puede simplificar su estado de cuenta mediante la eliminación de la declaración select y pasando el bloque directamente a any:

if [:a, :b, :c, :d].any? {|f| variable == f} 
+0

Aha! Creo que has clavado mi #include? problema - gracias, eso tiene perfecto sentido. Volver al problema en cuestión, también me gusta su método de pasar un bloque a cualquiera? - Eso se ve muy limpio para mí. – NeilS

1

Siempre he usado su segundo ejemplo, if [:a, :b, :c, :d].include? variable. Si bien esto presenta algunos problemas con las clases que sobrescriben ==, está perfectamente bien en la mayoría de las situaciones en que lo he necesitado (por lo general, verificar con símbolos).

+0

Gracias por sus comentarios. Me mordieron hoy por [: html,: xml] .include? (Request.format) siempre devolviendo false en una aplicación de Rails, ¡así que pensé que podría tener que salir de ese hábito! – NeilS

+2

Quizás podría escribir '[: html,: xml] .include? (Request.format.to_sym)' –

1

¿Qué tal:

if [:a, :b, :c, :d].index variable 
+0

Gracias por su comentario, se agradece. Creo que exhibe el mismo comportamiento que #include ?, aunque, presumiblemente por la misma razón que Pesto explica en su comentario. – NeilS

0

Lo que realmente está haciendo es ver si la variable es un miembro del conjunto [:a,:b,:c,:d] por lo semántico que se asigna al método include?.

El problema se encuentra con es debido a la naturaleza de pato tipificación de Rubí por lo que si usted desea conseguir en torno a que por qué no primero convertir en un símbolo:

if [:a, :b, :c, :d].include? variable.to_sym 
+0

Gracias por su comentario, está agradecido. Eso funciona en muchos casos, pero por supuesto no funcionará si el objeto en cuestión implementa una lógica adicional en su definición de igualdad. (Tal vez también se compara con una lista de sinónimos, por ejemplo.) – NeilS

3

Parece que Array#include? qué utiliza ==:

>> class AString < String 
>> def ==(other) 
>>  self[0] == other[0] 
>> end 
>> end 

>> asdf = AString.new "asdfg" 
=> "asdfg" 
>> b = AString.new 'aer' 
=> "aer" 

>> asdf == b 
=> true 

>> [asdf].include? b 
=> true 

La documentación Array#include? también lo explica.

+0

Gracias por su análisis; es apreciado Estaba siendo engañado por el problema que Pesto observa arriba, de ahí mi confusión. – NeilS

Cuestiones relacionadas