array - arreglos bidimensionales en ruby




Compruebe si existe un valor en una matriz en Ruby (15)

¡También hay al revés!

Supongamos que la matriz es [: editar,: actualizar,: crear,: mostrar] - bueno, tal vez los siete pecados mortales / reparadores completos :)

Y más juguete con la idea de sacar una acción válida de una cuerda, por ejemplo

A mi hermano le gustaría que actualice su perfil.

Solución

[ :edit, :update, :create, :show ].select{|v| v if "my brother would like me to update his profile".downcase =~ /[,|.| |]#{v.to_s}[,|.| |]/}

Tengo un valor 'Dog' y una matriz ['Cat', 'Dog', 'Bird'] .

¿Cómo verifico si existe en la matriz sin pasar por ella? ¿Hay una forma sencilla de comprobar si el valor existe, nada más?


¿Estás buscando include? :

>> ['Cat', 'Dog', 'Bird'].include? 'Dog'
=> true

Aquí hay una manera más de hacer esto:

arr = ['Cat', 'Dog', 'Bird']
e = 'Dog'

present = arr.size != (arr - [e]).size

El uso de Enumerable#include :

a = %w/Cat Dog Bird/

a.include? 'Dog'

O, si se realizan varias pruebas, 1 puede deshacerse del bucle (que incluso include? Ha) 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 para algunas búsquedas, el Hash [] y las operaciones de transposición dominan el perfil y son cada uno O (n) .


Esto le dirá no solo que existe, sino también cuántas veces aparece:

 a = ['Cat', 'Dog', 'Bird']
 a.count("Dog")
 #=> 1

Hay múltiples maneras de lograr esto. Algunos de ellos son los siguientes:

a = [1,2,3,4,5]

2.in? a  #=> true

8.in? a #=> false

a.member? 1 #=> true

a.member? 8 #=> false

Hecho de la diversión,

Puede usar * para verificar la pertenencia a una matriz en las expresiones de un case .

case element
when *array 
  ...
else
  ...
end

Observe el poco * en la cláusula when, esto verifica la pertenencia a la matriz.

Se aplica todo el comportamiento mágico habitual del operador splat, por ejemplo, si la array no es realmente una matriz sino un elemento único, coincidirá con ese elemento.


Para lo que vale la pena, 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? El método ejecutará una búsqueda lineal con O (n) complejidad que puede ser bastante desagradable dependiendo del tamaño de la matriz.

Si está trabajando con una matriz grande (ordenada), consideraría escribir un algoritmo de búsqueda binario que no debería ser demasiado difícil y tiene el peor de los casos de O (log n).

O si está utilizando Ruby 2.0, puede aprovechar bsearch .


Si necesita verificar varias veces para cualquier clave, convierta arr a hash , y ahora marque O (1)

arr = ['Cat', 'Dog', 'Bird']
hash = arr.map {|x| [x,true]}.to_h
 => {"Cat"=>true, "Dog"=>true, "Bird"=>true}
hash["Dog"]
 => true
hash["Insect"]
 => false

Rendimiento de Hash#has_key? versus include?

Parameter              Hash#has_key?                 Array#include 

Time Complexity         O(1) operation                O(n) operation 

Access Type             Accesses Hash[key] if it      Iterates through each element
                        returns any value then        of the array till it
                        true is returned to the       finds the value in Array
                        Hash#has_key? call
                        call    

Para una sola verificación de tiempo usando include? está bien


Si no quieres hacer un bucle, no hay forma de hacerlo con Arrays. 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 señale un punto determinado en la memoria. El ejemplo anterior hecho con un hash:

fake_array = {}
100.times{|i| fake_array["foo#{i}"] = 1}
fake_array.has_key?("foo99")
  => true

El inconveniente es que los conjuntos y las claves de hash solo pueden incluir elementos únicos y, si agrega muchos elementos, Ruby tendrá que volver a realizar todo el proceso después de cierto número de elementos para crear un nuevo mapa que se adapte a un mayor espacio de teclas. Para más información sobre esto, te recomiendo que veas MountainWest RubyConf 2014 - Big O en un Hash casero por Nathan Long

Aquí hay un punto de referencia:

require 'benchmark'
require 'set'

array = []
set   = Set.new

10_000.times do |i|
  array << "foo#{i}"
  set   << "foo#{i}"
end

Benchmark.bm do |x|
  x.report("array") { 10_000.times { array.include?("foo9999") } }
  x.report("set  ") { 10_000.times { set.include?("foo9999")   } }
end

Y los resultados:

      user     system      total        real
array  7.020000   0.000000   7.020000 (  7.031525)
set    0.010000   0.000000   0.010000 (  0.004816)

Si queremos no utilizar include? esto también funciona:

['cat','dog','horse'].select{ |x| x == 'dog' }.any?

Si quieres comprobar por un bloque, puedes probar alguno? ¿O todo?

%w{ant bear cat}.any? {|word| word.length >= 3}   #=> true  
%w{ant bear cat}.any? {|word| word.length >= 4}   #=> true  
[ nil, true, 99 ].any?                            #=> true  

Los detalles están aquí: http://ruby-doc.org/core-1.9.3/Enumerable.html
Mi inspiración viene de aquí: https://.com/a/10342734/576497


Tratar

['Cat', 'Dog', 'Bird'].include?('Dog')

Varias respuestas sugieren Array#include? , pero hay una advertencia importante: mirando 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)) {
            return Qtrue;
        }
    }
    return Qfalse;
}

La forma de probar la presencia de la palabra sin hacer un bucle es mediante la construcción de un trie para su matriz. Hay muchas implementaciones de trie por ahí (google "ruby trie"). Voy a utilizar rambling-trie en 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 hacer un bucle, en tiempo O(log n) , con la misma simplicidad sintáctica que Array#include? , usando sublinear Trie#include? :

trie.include? 'bird' #=> true
trie.include? 'duck' #=> false

array = [ 'Cat', 'Dog', 'Bird' ]
array.include?("Dog")




arrays