Declaración de caso con múltiples valores en cada bloque 'cuándo'

315

La mejor forma en que puedo describir lo que estoy buscando es mostrarle el código fallido que he probado hasta ahora:

case car
  when ['honda', 'acura'].include?(car)
    # code
  when 'toyota' || 'lexus'
    # code
end

Tengo alrededor de 4 o 5 whensituaciones diferentes que deberían ser activadas por aproximadamente 50 valores posibles diferentes de car. ¿Hay alguna manera de hacer esto con casebloques o debería intentar un ifbloque masivo ?

Mella
fuente

Respuestas:

669

En una casedeclaración, a ,es el equivalente de ||en una ifdeclaración.

case car
   when 'toyota', 'lexus'
      # code
end

Algunas otras cosas que puede hacer con una declaración de caso de Ruby

Charles Caldwell
fuente
1
Este enlace tiene un mejor resumen de las declaraciones de casos en Ruby (e incluye ejemplos de la sintaxis regexp y splat también).
rsenna
No sé por qué, pero esta extraña situación ocurre: Cuando escribo esto: when "toyota", "lexus", me sale: unexpected tSTRING_BEG, expecting keyword_do or '{' or '(' (SyntaxError). Sin embargo, cuando escribo esto: when "toyota","lexus"funciona. La única diferencia es un espacio después de la coma.
Furkan Ayhan
@FurkanAyhan Eso es extraño. Seguí adelante y probé el código solo para asegurarme de que funciona. Supongo que hay algo más en su código que lo convierte en un error como ese. ¿Es posible que te hayas olvidado de cerrar una cadena en algún lugar o algo así?
Charles Caldwell
1
bueno, esto funciona, pero como Ruby se enfoca en la facilidad del programador, me pregunto por qué no es compatible con el estándar || o o'? Esto es un poco confuso
Zia Ul Rehman Mughal
2
Ruby no es compatible oro ||aquí porque whentoma una serie de expresiones separadas por comas a la derecha, no un solo identificador. Debido a esto, si lo hubiera hecho when a or b, no está claro si esto debe tomarse como el equivalente de when a, bo when (a or b), el último de los cuales evalúa la expresión a or bprimero antes de arrojarla al cuándo. Es más sorprendente y menos fácil de manejar que el lenguaje tenga tokens que cambian el comportamiento en función del contexto, y luego no podría usar una orexpresión real en el lado derecho de un momento.
Taywee
99

Puede aprovechar el "splat" de Ruby o la sintaxis de aplanamiento.

Esto hace que las whencláusulas demasiado crecidas (tienes alrededor de 10 valores para probar por rama si lo entiendo correctamente), en mi opinión, son un poco más legibles. Además, puede modificar los valores para probar en tiempo de ejecución. Por ejemplo:

honda  = ['honda', 'acura', 'civic', 'element', 'fit', ...]
toyota = ['toyota', 'lexus', 'tercel', 'rx', 'yaris', ...]
...

if include_concept_cars
  honda += ['ev-ster', 'concept c', 'concept s', ...]
  ...
end

case car
when *toyota
  # Do something for Toyota cars
when *honda
  # Do something for Honda cars
...
end

Otro enfoque común sería usar un hash como tabla de despacho, con claves para cada valor cary valores que son un objeto invocable que encapsula el código que desea ejecutar.

pilcrow
fuente
Esto es lo que terminé usando, aunque me siento mal quitando la marca de verificación de alguien: D
Nick
Solución brillante para largas whencolas. Gracias por compartir.
Pistos
0

Otra buena manera de poner su lógica en los datos es algo como esto:

# Initialization.
CAR_TYPES = {
  foo_type: ['honda', 'acura', 'mercedes'],
  bar_type: ['toyota', 'lexus']
  # More...
}
@type_for_name = {}
CAR_TYPES.each { |type, names| names.each { |name| @type_for_name[type] = name } }

case @type_for_name[car]
when :foo_type
  # do foo things
when :bar_type
  # do bar things
end
Hew Wolff
fuente
No quiero ser grosero, pero voté en contra porque es menos eficiente tanto en tiempo como en espacio. También es más complejo y menos legible que las otras dos respuestas. ¿Cuál sería el beneficio de usar este método?
Nick
Pone toda su clasificación en un solo objeto. Ahora puede hacer cosas con ese objeto, como serializarlo y enviarlo a otra persona para explicar su lógica, o almacenarlo en una base de datos y permitir que las personas lo editen. (La lógica cambiará muy pronto cuando salgan nuevos modelos de automóviles, ¿verdad?) Puede buscar "conducido por una mesa".
Hew Wolff
YAGNI ("No lo vas a necesitar") puede aplicar aquí. El diseño sacrifica la eficiencia del tiempo / espacio y la legibilidad para un escenario que puede existir en el futuro pero que aún no existe. El costo se paga ahora, pero la recompensa nunca se puede cosechar.
Nick