usa el .include? Método . Devuelve un booleano que es lo que quieres. En su caso, simplemente escriba: ['Cat', 'Dog', 'Bird']. Include ('Dog') y debería devolver el verdadero booleano.
Jwan622
no utilizar incluir? método si desea verificar múltiples veces para que haya un valor diferente presente en la matriz o no porque incluye? cada vez iterará sobre la operación de toma de matriz O (n) para buscar cada vez, en lugar de hacer un hash hash = arr.map {|x| [x,true]}.to_h, ahora verifique si hash.has_key? 'Dog' devuelve verdadero o no
aqfaridi
3
Realmente no puedes hacerlo totalmente "sin recorrerlo". Es lógicamente imposible, la computadora simplemente no puede saber con certeza si la matriz contiene el elemento sin recorrer los elementos para verificar si alguno de ellos es el que está buscando. A menos que esté vacío, por supuesto. Entonces supongo que no necesitas un bucle.
Tim M.
Consulte los puntos de referencia a continuación para ver las pruebas de la diferencia de las diversas formas de encontrar un elemento en una matriz y un conjunto. stackoverflow.com/a/60404934/128421
Sintaxis alternativa:%w(Cat Dog Bird).include? 'Dog'
scarver2
184
A veces desearía que fuera "contiene" no incluir. Siempre lo mezclo con incluye.
Henley Chiu
19
Permítanme señalar que, internamente, #include?todavía realiza bucles. Sin embargo, el codificador se salva de escribir el bucle explícitamente. He agregado una respuesta que realiza la tarea realmente sin bucles.
Boris Stitnicky
8
@HenleyChiu I como se llamaba[ 'Dog', 'Bird', 'Cat' ].has? 'Dog'
44
@AlfonsoVergara Sí, cualquier solución para una matriz debe hacer algún tipo de bucle interno; no hay forma de probar la membresía de una matriz sin bucle. Si no desea realizar ningún bucle, incluso internamente, debe usar una estructura de datos diferente, como una tabla hash perfecta con claves de tamaño fijo. Dado que no hay forma de evaluar la membresía en una matriz sin hacer un bucle interno, interpreté la pregunta como "sin tener que escribir el bucle explícitamente"
Brian Campbell
250
Hay un in?método enActiveSupport (parte de Rails) desde v3.1, como lo señaló @campaterson. Entonces, dentro de Rails, o si puedes require 'active_support', puedes escribir:
'Unicorn'.in?(['Cat','Dog','Bird'])# => false
OTOH, no hay in operador o #in?método en Ruby, a pesar de que se ha propuesto antes, en particular por Yusuke Endoh, un miembro de primer nivel de ruby-core.
Como se ha señalado por otros, el método inverso include?existe, para todo Enumerables incluyendo Array, Hash, Set, Range:
Tenga en cuenta que si tiene muchos valores en su matriz, todos se verificarán uno después del otro (es decir O(n)), mientras que la búsqueda de un hash será de tiempo constante (es decir O(1)). Entonces, si su matriz es constante, por ejemplo, es una buena idea usar un Set en su lugar. P.ej:
Una prueba rápida revela que llamar include?a un elemento 10 Setes aproximadamente 3.5 veces más rápido que llamarlo al equivalente Array(si no se encuentra el elemento).
Una nota final de cierre: tenga cuidado al usar include?en un Range, hay sutilezas, así que consulte el documento y compárelo con cover?...
esta es la sintaxis anterior, mira ^^^ @ respuesta de brian
jahrichie
62
@jahrichie ¿qué consideras exactamente "sintaxis anterior" en esta respuesta, los paréntesis opcionales?
Dennis
3
Estoy de acuerdo @Dennis, esto no es más antiguo, los paréntesis son opcionales y en la mayoría de los casos una BUENA PRÁCTICA ... intente usar incluir sin paréntesis en una línea si la oración, por ejemplo, lo que quiero decir es que dependiendo de su caso usted debería o debe usar paréntesis o no (no está relacionado con las sintaxis "antiguas" de rubí)
d1jhoni1b
Esta es la única sintaxis que podría poner a trabajar dentro de una operación ternaria.
Michael Cameron
49
Uso Enumerable#include:
a =%w/CatDogBird/
a.include?'Dog'
O, si se realizan varias pruebas, 1 puede deshacerse del ciclo (que incluso include?tiene) y pasar de O (n) a O (1) con:
h =Hash[[a, a].transpose]
h['Dog']
1. Espero que esto sea obvio, pero para evitar objeciones: sí, solo por unas pocas búsquedas, las operaciones Hash [] y transposición dominan el perfil y son O (n) ellas mismas.
Muy útil si desea verificar alguna / todas esas cadenas están incluidas en otra cadena / constante
thanikkal
43
Ruby tiene once métodos para encontrar elementos en una matriz.
El preferido es include?o, para acceso repetido, crear un Set y luego llamar include?o member?.
Aquí están todos ellos:
array.include?(element)# preferred method
array.member?(element)
array.to_set.include?(element)
array.to_set.member?(element)
array.index(element)>0
array.find_index(element)>0
array.index {|each| each == element }>0
array.find_index {|each| each == element }>0
array.any?{|each| each == element }
array.find {|each| each == element }!=nil
array.detect {|each| each == element }!=nil
Todos devuelven un truevalor ish si el elemento está presente.
include?Es el método preferido. Utiliza un forbucle de lenguaje C internamente que se rompe cuando un elemento coincide con las rb_equal_opt/rb_equalfunciones internas . No puede ser mucho más eficiente a menos que cree un Conjunto para verificaciones de membresía repetidas.
VALUE
rb_ary_includes(VALUE ary, VALUE item){
long i;
VALUE e;for(i=0; i<RARRAY_LEN(ary); i++){
e = RARRAY_AREF(ary, i);
switch (rb_equal_opt(e, item)){caseQundef:if(rb_equal(e, item))returnQtrue;break;caseQtrue:returnQtrue;}}returnQfalse;}
member?no se redefine en la Arrayclase y utiliza una implementación no optimizada del Enumerablemódulo que literalmente enumera a través de todos los elementos:
static VALUE
member_i(RB_BLOCK_CALL_FUNC_ARGLIST(iter, args)){
struct MEMO *memo = MEMO_CAST(args);if(rb_equal(rb_enum_values_pack(argc, argv), memo->v1)){
MEMO_V2_SET(memo,Qtrue);
rb_iter_break();}returnQnil;}
static VALUE
enum_member(VALUE obj, VALUE val){
struct MEMO *memo = MEMO_NEW(val,Qfalse,0);
rb_block_call(obj, id_each,0,0, member_i,(VALUE)memo);return memo->v2;}
Ambos include?ymember? tienen complejidad O (n) tiempo desde que el tanto buscar la matriz para la primera aparición del valor esperado.
Podemos usar un Set para obtener el tiempo de acceso O (1) a costa de tener que crear primero una representación Hash de la matriz. Si verifica repetidamente la membresía en la misma matriz, esta inversión inicial puede pagar rápidamente. Setno está implementado en C pero como clase simple de Ruby, sigue siendo el tiempo de acceso O (1) del subyacente@hash hace que valga la pena.
Como puede ver, la clase Set solo crea una @hashinstancia interna , asigna todos los objetos truey luego verifica la membresía usandoHash#include? que se implementa con el tiempo de acceso O (1) en la clase Hash.
No discutiré los otros siete métodos, ya que todos son menos eficientes.
En realidad, hay incluso más métodos con complejidad O (n) más allá de los 11 enumerados anteriormente, pero decidí no enumerarlos ya que escanean toda la matriz en lugar de romper en la primera coincidencia.
No uses estos:
# bad examples
array.grep(element).any?
array.select {|each| each == element }.size >0...
¡Qué descarado decir que Ruby tiene exactamente 11 formas de hacer cualquier cosa! Tan pronto como diga que alguien señalará que se perdió el # 12, luego el # 13, y así sucesivamente. Para exponer mi punto de vista, sugeriré otras formas, pero primero permítame cuestionar las 11formas que ha enumerado. Primero, apenas puede contar indexy find_index(o findy detect) como métodos separados, ya que son solo nombres diferentes para el mismo método. En segundo lugar, todas las expresiones que terminan con > 0son incorrectas, lo que estoy seguro fue un descuido. (cont.)
Cary Swoveland
... arr.index(e), por ejemplo, devuelve 0if arr[0] == e. Recuperará arr.index(e)devoluciones nilsi eno está presente. indexsin embargo, no se puede usar si uno está buscando nilen arr. (Mismo problema con rindex, que no está en la lista). Convertir la matriz en un conjunto y luego emplear métodos de conjunto es un poco exagerado. ¿Por qué no convertir luego a un hash (con claves de la matriz y valores arbitrarios) y luego usar métodos hash? Incluso si la conversión a un conjunto está bien, existen otros métodos de conjunto que podrían usarse, como !arr.to_set.add?(e). (cont.)
Cary Swoveland
... Según lo prometido, aquí hay algunas más métodos que podrían utilizarse: arr.count(e) > 0, arr != arr.dup.delete(e) , arr != arr - [e]y arr & [e] == [e]. También se podría emplear selecty reject.
Cary Swoveland
Recomiendo usar un Set si el criterio es que no se permiten duplicados, y saber si existe un elemento en particular en la lista. Set es MUY mucho más rápido. Las matrices realmente no deberían usarse cuando se necesita buscar; Se usan mejor como una cola donde las cosas se almacenan temporalmente para ser procesadas en orden. Hash y Set son mejores para ver si algo existe.
The Tin Man
30
Varias respuestas sugieren Array#include?, pero hay una advertencia importante: mirar la fuente, incluso Array#include?realiza bucles:
rb_ary_includes(VALUE ary, VALUE item){
long i;for(i=0; i<RARRAY_LEN(ary); i++){if(rb_equal(RARRAY_AREF(ary, i), item)){returnQtrue;}}returnQfalse;}
La forma de probar la presencia de la palabra sin bucle es construyendo un trie para su matriz. Hay muchas implementaciones de trie por ahí (google "ruby trie"). Usaré rambling-trieen este ejemplo:
a =%w/cat dog bird/
require 'rambling-trie'# if necessary, gem install rambling-trie
trie =Rambling::Trie.create {|trie| a.each do|e| trie << e end}
Y ahora estamos listos para probar la presencia de varias palabras en su matriz sin recorrerla, a O(log n)tiempo, con la misma simplicidad sintáctica que Array#include?, usando sublinear Trie#include?:
a.each do ... endUmm ... no estoy seguro de cómo eso no es un bucle
tckmn
27
Tenga en cuenta que esto realmente incluye un bucle; todo lo que no sea O (1) incluye algún tipo de bucle. Simplemente resulta ser un bucle sobre los caracteres de la cadena de entrada. También tenga en cuenta que una respuesta ya mencionada Set#include?para las personas que están preocupadas por la eficiencia; junto con el uso de símbolos en lugar de cadenas, puede ser un caso promedio O (1) (si usa cadenas, entonces simplemente calcular el hash es O (n) donde n es la longitud de la cadena). O si desea usar bibliotecas de terceros, puede usar un hash perfecto, que es O (1) peor de los casos.
Brian Campbell
44
AFAIK, Setutiliza hashes para indexar sus miembros, por lo que en realidad Set#include?debería ser de complejidad O (1) para un bien distribuido Set(más específicamente O (tamaño de entrada) para el hash, y O (log (n / bucket-number)) para la búsqueda)
Uri Agassi
11
El costo de crear y mantener el trie es igual. Si está realizando muchas operaciones de búsqueda en la matriz, entonces vale la pena el costo de memoria y tiempo de llenar un trie y mantenerlo, pero para un solo, o incluso cientos o miles de controles, O (n) es perfectamente adecuado. Otra opción que no requiere agregar dependencias sería ordenar la matriz o mantenerla en orden, en cuyo caso se puede usar una operación de búsqueda binaria O (lg n) para verificar la inclusión.
hablando
1
@speakingcode, puede tener razón desde el punto de vista pragmático. Pero el OP pide "verificar si el valor existe, nada más, sin bucle". Cuando escribí esta respuesta, había muchas soluciones pragmáticas aquí, pero ninguna que realmente cumpliera con el requisito literal del autor de la pregunta. Su observación de que los BST están relacionados con los intentos es correcta, pero para las cadenas, trie es la herramienta adecuada para el trabajo, incluso Wikipedia lo sabe . La complejidad de construir y mantener un trie bien implementado es sorprendentemente favorable.
Boris Stitnicky
18
Si no desea realizar un bucle, no hay forma de hacerlo con matrices. Deberías usar un Set en su lugar.
require 'set'
s =Set.new
100.times{|i| s <<"foo#{i}"}
s.include?("foo99")=>true[1,2,3,4,5,6,7,8].to_set.include?(4)=>true
Los conjuntos funcionan internamente como Hashes, por lo que Ruby no necesita recorrer la colección para encontrar elementos, ya que, como su nombre lo indica, genera hashes de las claves y crea un mapa de memoria para que cada hash apunte a un cierto punto en la memoria. El ejemplo anterior hecho con un Hash:
La desventaja es que las teclas Sets y Hash solo pueden incluir elementos únicos y si agrega muchos elementos, Ruby tendrá que volver a mostrar todo después de cierto número de elementos para construir un nuevo mapa que se adapte a un espacio de teclas más grande. Para más información sobre esto, te recomiendo que veas " MountainWest RubyConf 2014 - Big O in a Homemade Hash por Nathan Long ".
Si usa detect, al menos puede reducir el bucle. detect se detendrá en el primer elemento 'detectado' (el bloque pasado para el elemento se evalúa como verdadero). Además, puede decirle a detectar qué hacer si no se detecta nada (puede pasar una lambda).
aenw
1
@aenw no se include?detiene al primer golpe?
Kimmo Lehto
Estás absolutamente en lo correcto. Estoy tan acostumbrado a usar detect que me había olvidado de incluir. gracias por tu comentario, aseguró que actualicé mis conocimientos.
aenw
include?se detiene en el primer hit pero si ese hit está al final de la lista ... Cualquier solución que se base en una matriz para almacenamiento tendrá un rendimiento degradante a medida que la lista crezca, especialmente cuando tenga que encontrar un elemento al final de la lista lista. Hash y Set no tienen ese problema, ni tampoco una lista ordenada y una búsqueda binaria.
The Tin Man
Eso es más o menos de lo que se trataba esta respuesta en primer lugar :)
Kimmo Lehto
17
Esta es otra forma de hacer esto: use el Array#index método.
Devuelve el índice de la primera aparición del elemento en la matriz.
Por ejemplo:
a =['cat','dog','horse']if a.index('dog')
puts "dog exists in the array"end
index() También puede tomar un bloque:
Por ejemplo:
a =['cat','dog','horse']
puts a.index {|x| x.match /o/}
Esto devuelve el índice de la primera palabra en la matriz que contiene la letra 'o'.
indextodavía itera sobre la matriz, solo devuelve el valor del elemento.
The Tin Man
13
Hecho de la diversión,
Puede usar *para verificar la membresía de una matriz en caseexpresiones.
case element
when*array
...else...end
Note el pequeño * en la cláusula when, esto verifica la membresía en la matriz.
Se aplica todo el comportamiento mágico habitual del operador splat, por lo que, por ejemplo, si arrayno es realmente una matriz sino un solo elemento, coincidirá con ese elemento.
También sería un primer cheque lento en una declaración de caso, por lo que lo usaría en el último whenposible para que otros cheques más rápidos se eliminen rápidamente.
el hombre de hojalata
9
Hay múltiples formas de lograr esto. Algunos de ellos son los siguientes:
a =[1,2,3,4,5]2.in? a #=> true8.in? a #=> false
a.member?1#=> true
a.member?8#=> false
Parámetro Hash # has_key? Array # include
Complejidad de tiempo Operación O (1) Operación O (n)
Tipo de acceso Accede al hash [clave] si se itera a través de cada elemento
devuelve cualquier valor de la matriz hasta que
true se devuelve a encuentra el valor en Array
Hash # has_key? llamada
llamada
Para el control de una sola vez, usar include?está bien
¿Todavía no estás recorriendo el conjunto para convertirlo en un hash?
chrisjacob
2
Sí, lo hice, pero ahora tengo una respuesta precalculada para verificar si existe algún elemento en la matriz o no. Ahora, la próxima vez que busque otra palabra, tomará O (1) para la consulta, aunque el cálculo previo tomará O (n). En realidad he usado incluir? en mi aplicación dentro del bucle para verificar si un elemento en particular existe en la matriz o no, arruina el rendimiento, verificó en ruby-prof, ese fue el cuello de botella
aqfaridi
1
.... pero O (n) espacio y también, no, es O (n) tiempo, porque como @ chris72205 señala correctamente, primero debe iterar a través de su matriz. O (1) + O (n) = O (n). Entonces, de hecho, esto es mucho peor que incluir?
Rambatino
Amigo, solo estaba diciendo que no utilices incluir el bucle interno, para la comprobación de tiempo único, usar incluir está bien. Entonces, lea primero el caso de uso, es mejor si necesita verificar varias veces dentro del bucle.
aqfaridi
Convertir una matriz en un hash es costoso, pero usar una matriz para buscar es la estructura incorrecta. Las matrices son mejores como colas donde el orden puede ser importante; Los hashes y conjuntos son mejores cuando la inclusión / existencia / unicidad son importantes. Comience con el contenedor correcto y el problema es discutible.
The Tin Man
4
Esto le dirá no solo que existe, sino también cuántas veces aparece:
Sin embargo, no tiene sentido usar esto a menos que desee saber cuántas veces aparece, sin embargo, ya .any?que volverá tan pronto como encuentre el primer elemento coincidente, .countsiempre procesará toda la matriz.
Zaz
Si bien esta técnica dirá si algo existe, sino que también es NO la manera correcta de hacerlo si se preocupan por la velocidad.
El hombre de hojalata
4
Por lo que vale, los documentos de Ruby son un recurso increíble para este tipo de preguntas.
También tomaría nota de la longitud de la matriz que está buscando. El include?método ejecutará una búsqueda lineal con complejidad O (n) que puede volverse bastante fea dependiendo del tamaño de la matriz.
Si está trabajando con una matriz grande (ordenada), consideraría escribir un algoritmo de búsqueda binaria que no debería ser demasiado difícil y tiene el peor caso de O (log n).
O si está utilizando Ruby 2.0, puede aprovecharlo bsearch.
Una búsqueda binaria supone que la matriz está ordenada (u ordenada de alguna forma), lo que puede ser costoso para matrices grandes, a menudo negando la ventaja.
The Tin Man
Una búsqueda binaria también requiere que todos los pares de elementos sean comparables <=>, lo cual no siempre es el caso. Supongamos, por ejemplo, que los elementos de la matriz son hashes.
Cary Swoveland
1
@CarySwoveland debería estar más o menos implícito que los elementos dentro de una matriz ordenada son comparables.
davissp14
4
Puedes probar:
Ejemplo: si Cat y Dog existen en la matriz:
(['Cat','Dog','Bird']&['Cat','Dog']).size ==2#or replace 2 with ['Cat','Dog].size
Su expresión regular, /[,|.| |]#{v.to_s}[,|.| |]/me hace pensar que quería encontrar 'el nombre de la acción rodeado de uno de: coma, punto, espacio o nada', pero hay algunos errores sutiles. "|update|"volvería [:update]y "update"volvería []. Las clases de caracteres ( [...]) no usan tuberías ( |) para separar los caracteres. Incluso si los cambiamos a grupos ( (...)), no puede hacer coincidir un carácter vacío. Entonces, la expresión regular que probablemente querías es/(,|\.| |^)#{v.to_s}(,|\.| |$)/
bkDJ
el regex está bien (revisado rubular.com) - y @Rambatino: por qué sería como Amazon Echo, por ejemplo;) Podría decir: "por favor agregue pollo a mi lista de compras" (y, bueno, entonces tendría que agregue el: agregue a la matriz, pero creo que obtendrá la esencia de esto;)
walt_die
1
"la expresión regular está bien (revisado rubular.com)". No está bien. Su expresión regular no coincidirá con una palabra clave al principio o al final de una cadena (por ejemplo, "actualizar el perfil de mi hermano"). Si no desea hacer coincidir el principio o el final, entonces su expresión regular todavía no está bien porque la clase de caracteres a ambos lados de la palabra clave debería ser/[,. ]/
O el uso array.any?{|x| x == 'Dog'}si usted no quiere verdadero / falso (no el valor), sino que también quiere comparar contra un bloque de esta manera.
mahemoff
0
Aquí hay una forma más de hacer esto:
arr =['Cat','Dog','Bird']
e ='Dog'
present = arr.size !=(arr -[e]).size
¡Esta es una forma terriblemente ineficiente de hacer esto! No estoy votando porque no es técnicamente incorrecto, y alguien podría aprender algo sobre Ruby al leerlo, pero hay muchas mejores respuestas arriba.
jibberia
Conehead, puede simplificar a arr != arr - [e]. arr & [e] == [e]Es otra forma en la misma línea.
Cary Swoveland
@CarySwoveland No te burles del sombrero de un mago ;-)
Wand Maker
Me refería a la cabeza del mago, no al sombrero, con el mayor respeto.
si no desea usar include?, primero puede envolver el elemento en una matriz y luego verificar si el elemento envuelto es igual a la intersección de la matriz y el elemento envuelto. Esto devolverá un valor booleano basado en la igualdad.
Siempre me parece interesante ejecutar algunos puntos de referencia para ver la velocidad relativa de las diversas formas de hacer algo.
Encontrar un elemento de matriz al comienzo, en el medio o al final afectará cualquier búsqueda lineal, pero apenas afectará una búsqueda contra un Conjunto.
La conversión de una matriz en un conjunto causará un impacto en el tiempo de procesamiento, así que cree el conjunto desde una matriz una vez o comience con un conjunto desde el principio.
Lo cual, cuando se ejecuta en mi computadora portátil Mac OS, da como resultado:
Ruby v.2.7.0--------------------First--------------------Running each test 65536 times.Test will take about 5 seconds.
_array_include? is similar to _array_index
_array_index is similar to _array_find_index
_array_find_index is faster than _array_any_each by 2x±1.0
_array_any_each is similar to _array_index_each
_array_index_each is similar to _array_find_index_each
_array_find_index_each is faster than _array_member? by 4x±1.0
_array_member? is faster than _array_detect_each by 2x±1.0
_array_detect_each is similar to _array_find_each
--------------------Middle--------------------Running each test 32 times.Test will take about 2 seconds.
_array_include? is similar to _array_find_index
_array_find_index is similar to _array_index
_array_index is faster than _array_member? by 2x±0.1
_array_member? is faster than _array_index_each by 2x±0.1
_array_index_each is similar to _array_find_index_each
_array_find_index_each is similar to _array_any_each
_array_any_each is faster than _array_detect_each by 30.000000000000004%±10.0%
_array_detect_each is similar to _array_find_each
--------------------Last--------------------Running each test 16 times.Test will take about 2 seconds.
_array_include? is faster than _array_find_index by 10.000000000000009%±10.0%
_array_find_index is similar to _array_index
_array_index is faster than _array_member? by 3x±0.1
_array_member? is faster than _array_find_index_each by 2x±0.1
_array_find_index_each is similar to _array_index_each
_array_index_each is similar to _array_any_each
_array_any_each is faster than _array_detect_each by 30.000000000000004%±10.0%
_array_detect_each is similar to _array_find_each
--------------------Sets vs.Array.include?----------------------------------------First--------------------Running each test 65536 times.Test will take about 1 second.
_array_include? is similar to _set_include?
_set_include? is similar to _set_member?--------------------Middle--------------------Running each test 65536 times.Test will take about 2 minutes.
_set_member? is similar to _set_include?
_set_include? is faster than _array_include? by 1400x±1000.0--------------------Last--------------------Running each test 65536 times.Test will take about 4 minutes.
_set_member? is similar to _set_include?
_set_include? is faster than _array_include? by 3000x±1000.0
Básicamente, los resultados me dicen que use un Set para todo si voy a buscar la inclusión, a menos que pueda garantizar que el primer elemento sea el que quiero, lo cual no es muy probable. Hay algo de sobrecarga cuando se insertan elementos en un hash, pero los tiempos de búsqueda son mucho más rápidos que no creo que eso deba considerarse. Nuevamente, si necesita buscarlo, no use una matriz, use un conjunto. (O un hash)
Cuanto más pequeña sea la matriz, más rápido se ejecutarán los métodos de matriz, pero todavía no van a seguir el ritmo, aunque en matrices pequeñas la diferencia puede ser pequeña.
"Primero", "Medio" y "Última" reflejan el uso de first, size / 2y lastpara ARRAYel bienestar elemento buscado. Ese elemento se usará al buscar las variables ARRAYy SET.
Se realizaron cambios menores en los métodos que se comparaban > 0porque la prueba debería ser >= 0para indexpruebas de tipo.
Más información sobre Fruity y su metodología está disponible en su archivo README .
hash = arr.map {|x| [x,true]}.to_h
, ahora verifique sihash.has_key? 'Dog'
devuelve verdadero o noRespuestas:
Estas buscando
include?
:fuente
%w(Cat Dog Bird).include? 'Dog'
#include?
todavía realiza bucles. Sin embargo, el codificador se salva de escribir el bucle explícitamente. He agregado una respuesta que realiza la tarea realmente sin bucles.[ 'Dog', 'Bird', 'Cat' ].has? 'Dog'
Hay un
in?
método enActiveSupport
(parte de Rails) desde v3.1, como lo señaló @campaterson. Entonces, dentro de Rails, o si puedesrequire 'active_support'
, puedes escribir:OTOH, no hay
in
operador o#in?
método en Ruby, a pesar de que se ha propuesto antes, en particular por Yusuke Endoh, un miembro de primer nivel de ruby-core.Como se ha señalado por otros, el método inverso
include?
existe, para todoEnumerable
s incluyendoArray
,Hash
,Set
,Range
:Tenga en cuenta que si tiene muchos valores en su matriz, todos se verificarán uno después del otro (es decir
O(n)
), mientras que la búsqueda de un hash será de tiempo constante (es decirO(1)
). Entonces, si su matriz es constante, por ejemplo, es una buena idea usar un Set en su lugar. P.ej:Una prueba rápida revela que llamar
include?
a un elemento 10Set
es aproximadamente 3.5 veces más rápido que llamarlo al equivalenteArray
(si no se encuentra el elemento).Una nota final de cierre: tenga cuidado al usar
include?
en unRange
, hay sutilezas, así que consulte el documento y compárelo concover?
...fuente
#in?
en su núcleo, si está utilizando Rails, está disponible. api.rubyonrails.org/classes/Object.html#method-i-in-3F (Sé que esta es una pregunta de Ruby, no de Rails, pero puede ayudar a cualquiera que quiera usarla#in?
en Rails. Parece que se agregó en Rails 3.1 apidock.com/rails/Object/in%3FTratar
fuente
Uso
Enumerable#include
:O, si se realizan varias pruebas, 1 puede deshacerse del ciclo (que incluso
include?
tiene) y pasar de O (n) a O (1) con:1. Espero que esto sea obvio, pero para evitar objeciones: sí, solo por unas pocas búsquedas, las operaciones Hash [] y transposición dominan el perfil y son O (n) ellas mismas.
fuente
Si desea verificar por un bloque, puede intentarlo
any?
oall?
.Ver Enumerable para más información.
Mi inspiración vino de " evaluar si la matriz tiene algún artículo en rubí "
fuente
Ruby tiene once métodos para encontrar elementos en una matriz.
El preferido es
include?
o, para acceso repetido, crear un Set y luego llamarinclude?
omember?
.Aquí están todos ellos:
Todos devuelven un
true
valor ish si el elemento está presente.include?
Es el método preferido. Utiliza unfor
bucle de lenguaje C internamente que se rompe cuando un elemento coincide con lasrb_equal_opt/rb_equal
funciones internas . No puede ser mucho más eficiente a menos que cree un Conjunto para verificaciones de membresía repetidas.member?
no se redefine en laArray
clase y utiliza una implementación no optimizada delEnumerable
módulo que literalmente enumera a través de todos los elementos:Traducido al código Ruby, esto hace lo siguiente:
Ambos
include?
ymember?
tienen complejidad O (n) tiempo desde que el tanto buscar la matriz para la primera aparición del valor esperado.Podemos usar un Set para obtener el tiempo de acceso O (1) a costa de tener que crear primero una representación Hash de la matriz. Si verifica repetidamente la membresía en la misma matriz, esta inversión inicial puede pagar rápidamente.
Set
no está implementado en C pero como clase simple de Ruby, sigue siendo el tiempo de acceso O (1) del subyacente@hash
hace que valga la pena.Aquí está la implementación de la clase Set:
Como puede ver, la clase Set solo crea una
@hash
instancia interna , asigna todos los objetostrue
y luego verifica la membresía usandoHash#include?
que se implementa con el tiempo de acceso O (1) en la clase Hash.No discutiré los otros siete métodos, ya que todos son menos eficientes.
En realidad, hay incluso más métodos con complejidad O (n) más allá de los 11 enumerados anteriormente, pero decidí no enumerarlos ya que escanean toda la matriz en lugar de romper en la primera coincidencia.
No uses estos:
fuente
11
formas que ha enumerado. Primero, apenas puede contarindex
yfind_index
(ofind
ydetect
) como métodos separados, ya que son solo nombres diferentes para el mismo método. En segundo lugar, todas las expresiones que terminan con> 0
son incorrectas, lo que estoy seguro fue un descuido. (cont.)arr.index(e)
, por ejemplo, devuelve0
ifarr[0] == e
. Recuperaráarr.index(e)
devolucionesnil
sie
no está presente.index
sin embargo, no se puede usar si uno está buscandonil
enarr
. (Mismo problema conrindex
, que no está en la lista). Convertir la matriz en un conjunto y luego emplear métodos de conjunto es un poco exagerado. ¿Por qué no convertir luego a un hash (con claves de la matriz y valores arbitrarios) y luego usar métodos hash? Incluso si la conversión a un conjunto está bien, existen otros métodos de conjunto que podrían usarse, como!arr.to_set.add?(e)
. (cont.)arr.count(e) > 0
,arr != arr.dup.delete(e)
,arr != arr - [e]
yarr & [e] == [e]
. También se podría emplearselect
yreject
.Varias respuestas sugieren
Array#include?
, pero hay una advertencia importante: mirar la fuente, inclusoArray#include?
realiza bucles:La forma de probar la presencia de la palabra sin bucle es construyendo un trie para su matriz. Hay muchas implementaciones de trie por ahí (google "ruby trie"). Usaré
rambling-trie
en este ejemplo:Y ahora estamos listos para probar la presencia de varias palabras en su matriz sin recorrerla, a
O(log n)
tiempo, con la misma simplicidad sintáctica queArray#include?
, usando sublinearTrie#include?
:fuente
a.each do ... end
Umm ... no estoy seguro de cómo eso no es un bucleSet#include?
para las personas que están preocupadas por la eficiencia; junto con el uso de símbolos en lugar de cadenas, puede ser un caso promedio O (1) (si usa cadenas, entonces simplemente calcular el hash es O (n) donde n es la longitud de la cadena). O si desea usar bibliotecas de terceros, puede usar un hash perfecto, que es O (1) peor de los casos.Set
utiliza hashes para indexar sus miembros, por lo que en realidadSet#include?
debería ser de complejidad O (1) para un bien distribuidoSet
(más específicamente O (tamaño de entrada) para el hash, y O (log (n / bucket-number)) para la búsqueda)Si no desea realizar un bucle, no hay forma de hacerlo con matrices. Deberías usar un Set en su lugar.
Los conjuntos funcionan internamente como Hashes, por lo que Ruby no necesita recorrer la colección para encontrar elementos, ya que, como su nombre lo indica, genera hashes de las claves y crea un mapa de memoria para que cada hash apunte a un cierto punto en la memoria. El ejemplo anterior hecho con un Hash:
La desventaja es que las teclas Sets y Hash solo pueden incluir elementos únicos y si agrega muchos elementos, Ruby tendrá que volver a mostrar todo después de cierto número de elementos para construir un nuevo mapa que se adapte a un espacio de teclas más grande. Para más información sobre esto, te recomiendo que veas " MountainWest RubyConf 2014 - Big O in a Homemade Hash por Nathan Long ".
Aquí hay un punto de referencia:
Y los resultados:
fuente
include?
detiene al primer golpe?include?
se detiene en el primer hit pero si ese hit está al final de la lista ... Cualquier solución que se base en una matriz para almacenamiento tendrá un rendimiento degradante a medida que la lista crezca, especialmente cuando tenga que encontrar un elemento al final de la lista lista. Hash y Set no tienen ese problema, ni tampoco una lista ordenada y una búsqueda binaria.Esta es otra forma de hacer esto: use el
Array#index
método.Devuelve el índice de la primera aparición del elemento en la matriz.
Por ejemplo:
index()
También puede tomar un bloque:Por ejemplo:
Esto devuelve el índice de la primera palabra en la matriz que contiene la letra 'o'.
fuente
index
todavía itera sobre la matriz, solo devuelve el valor del elemento.Hecho de la diversión,
Puede usar
*
para verificar la membresía de una matriz encase
expresiones.Note el pequeño
*
en la cláusula when, esto verifica la membresía en la matriz.Se aplica todo el comportamiento mágico habitual del operador splat, por lo que, por ejemplo, si
array
no es realmente una matriz sino un solo elemento, coincidirá con ese elemento.fuente
when
posible para que otros cheques más rápidos se eliminen rápidamente.Hay múltiples formas de lograr esto. Algunos de ellos son los siguientes:
fuente
Object#in?
solo se agregó a Rails (es decirActiveSupport
) v3.1 +. No está disponible en el núcleo de Ruby.Si necesita verificar múltiples veces para cualquier clave, convierta
arr
ahash
, y ahora ingrese O (1)Rendimiento de Hash # has_key? versus Array # include?
Para el control de una sola vez, usar
include?
está bienfuente
Esto le dirá no solo que existe, sino también cuántas veces aparece:
fuente
.any?
que volverá tan pronto como encuentre el primer elemento coincidente,.count
siempre procesará toda la matriz.Por lo que vale, los documentos de Ruby son un recurso increíble para este tipo de preguntas.
También tomaría nota de la longitud de la matriz que está buscando. El
include?
método ejecutará una búsqueda lineal con complejidad O (n) que puede volverse bastante fea dependiendo del tamaño de la matriz.Si está trabajando con una matriz grande (ordenada), consideraría escribir un algoritmo de búsqueda binaria que no debería ser demasiado difícil y tiene el peor caso de O (log n).
O si está utilizando Ruby 2.0, puede aprovecharlo
bsearch
.fuente
<=>
, lo cual no siempre es el caso. Supongamos, por ejemplo, que los elementos de la matriz son hashes.Puedes probar:
Ejemplo: si Cat y Dog existen en la matriz:
En vez de:
Nota:
member?
yinclude?
son lo mismo.¡Esto puede hacer el trabajo en una línea!
fuente
Si no queremos usar
include?
esto también funciona:fuente
fuente
['Cat', nil, 'Dog'].detect { |x| x == nil } #=> nil
. Fuenil
encontrado?¿Qué tal este camino?
fuente
Si está tratando de hacer esto en una prueba de unidad MiniTest , puede usarla
assert_includes
. Ejemplo:fuente
Hay otra forma de evitar esto.
Supongamos que la matriz es
[ :edit, :update, :create, :show ]
, bueno, tal vez los siete pecados mortales / relajantes .Y más juguete con la idea de extraer una acción válida de una cadena:
Entonces:
fuente
/[,|.| |]#{v.to_s}[,|.| |]/
me hace pensar que quería encontrar 'el nombre de la acción rodeado de uno de: coma, punto, espacio o nada', pero hay algunos errores sutiles."|update|"
volvería[:update]
y"update"
volvería[]
. Las clases de caracteres ([...]
) no usan tuberías (|
) para separar los caracteres. Incluso si los cambiamos a grupos ((...)
), no puede hacer coincidir un carácter vacío. Entonces, la expresión regular que probablemente querías es/(,|\.| |^)#{v.to_s}(,|\.| |$)/
/[,. ]/
Si desea devolver el valor no solo verdadero o falso, use
Esto devolverá 'Perro' si existe en la lista; de lo contrario, será nulo.
fuente
array.any?{|x| x == 'Dog'}
si usted no quiere verdadero / falso (no el valor), sino que también quiere comparar contra un bloque de esta manera.Aquí hay una forma más de hacer esto:
fuente
arr != arr - [e]
.arr & [e] == [e]
Es otra forma en la misma línea.fuente
fuente
in?
requiereActiveSupport
que serán importados:require active_support
.si no desea usar
include?
, primero puede envolver el elemento en una matriz y luego verificar si el elemento envuelto es igual a la intersección de la matriz y el elemento envuelto. Esto devolverá un valor booleano basado en la igualdad.fuente
Siempre me parece interesante ejecutar algunos puntos de referencia para ver la velocidad relativa de las diversas formas de hacer algo.
Encontrar un elemento de matriz al comienzo, en el medio o al final afectará cualquier búsqueda lineal, pero apenas afectará una búsqueda contra un Conjunto.
La conversión de una matriz en un conjunto causará un impacto en el tiempo de procesamiento, así que cree el conjunto desde una matriz una vez o comience con un conjunto desde el principio.
Aquí está el código de referencia:
Lo cual, cuando se ejecuta en mi computadora portátil Mac OS, da como resultado:
Básicamente, los resultados me dicen que use un Set para todo si voy a buscar la inclusión, a menos que pueda garantizar que el primer elemento sea el que quiero, lo cual no es muy probable. Hay algo de sobrecarga cuando se insertan elementos en un hash, pero los tiempos de búsqueda son mucho más rápidos que no creo que eso deba considerarse. Nuevamente, si necesita buscarlo, no use una matriz, use un conjunto. (O un hash)
Cuanto más pequeña sea la matriz, más rápido se ejecutarán los métodos de matriz, pero todavía no van a seguir el ritmo, aunque en matrices pequeñas la diferencia puede ser pequeña.
"Primero", "Medio" y "Última" reflejan el uso de
first
,size / 2
ylast
paraARRAY
el bienestar elemento buscado. Ese elemento se usará al buscar las variablesARRAY
ySET
.Se realizaron cambios menores en los métodos que se comparaban
> 0
porque la prueba debería ser>= 0
paraindex
pruebas de tipo.Más información sobre Fruity y su metodología está disponible en su archivo README .
fuente