Mi nombre es Fernando Briano y soy programador.

Arrays en Ruby

Ruby

Ruby

Hoy voy a compartir mis apuntes sobre Arrays en Ruby. Como comentaba en posts anteriores, vengo estudiando con el libro Programming Ruby 1.9: The Pragmatic Programmers’ Guide. Vengo acompañando la lectura con los Ruby Koans, y algunos video tutoriales. Ya repasé lo de Rails For Zombies, y descubrí otro excelente recurso que son los RailsCasts. Vamos a ver si en algún momento tenemos algo escrito en Ruby para compartir 🙂

Vamos entonces con estructuras de datos de Ruby. Los Arrays y Hashes son dos clases creadas para el manejo de colecciones:

La maestría en estas dos clases es clave para ser un programador Ruby efectivo. Esta maestría puede llevar tiempo, porque ambas clases tienen interfaces muy grandes.

Teniendo en cuenta esta cita del libro, veamos una definición bien específica de qué es un Array en Ruby:

Arrays
Colección de referencias a objetos.

En Ruby, las variables guardan la referencia a un objeto, y no el objeto en sí. Cada referencia a un objeto ocupa una posición en el array identificado por un índice entero.

a = [3.141592, "pi", 42]
a.class		# Array
a.length	# 3
a[0]		# 3.141592
a[2]		# 42
a[3]		# nil
a[15]		# nil
 
b = Array.new
b.class		# Array
b.length	# 0
b[0] = "Uno"
b[1] = "Dos"
b		# ["Uno", "Dos"]

Se indexan los elementos usando el operador [], un método de instancia de la clase Array que puede ser sobrescrito. Llamar a una posición de un entero positivo, retorna el objeto en ese lugar o nil si no hay nada ahí. Con los índices negativos, se cuenta desde el final siendo -1 el último elemento del array, y -array.length el primero.

a = [1,  5,  6, 38, 95]
#    0,  1,  2,  3,  4	índices positivos
#   -5, -4, -3, -2, -1	índices negativos
 
a[-1] 		# 95
a[-3] 		# 6
a[-56]		# nil

Se pueden indexar con un par de números (inicio, cantidad). Esto devuelve un nuevo array con referencias a la cantidad de objetos comenzando en la posición inicio.

a = [1, 5, 6, 38, 95]
a[1,3]		# [5, 6, 38]
a[-3, 2]	# [6, 38]

También se pueden usar rangos. Ruby implementa un objeto para representar rangos como los meses de Enero a Diciembre, secuencias de números y demás. En el caso de los arrays, se usan los rangos que implementan secuencias (también implementan condiciones e intervalos). Estos funcionan así:

1..10
1...10

Cuando se usan los tres puntos, se excluye al último elemento del rango.

De esta manera, podemos acceder a los elementos de un array así:

a = [1, 5, 6, 38, 95]
a[1..3]		# [5, 6, 38]
a[-4..4]	# [5, 6, 38, 95]

El operador [] tiene un operador []= para setear elementos en el array. Si se usa un solo índice entero, el elemento en esa posición se reemplaza con lo que haya a la derecha de la asignación. Si quedan espacios sin asignar en el medio, estos se llenan con nil.

a = [1, 5, 6, 38, 95]
a[1] = 'Stegosaurus'	#[1, 'Stegosaurus', 6, 38, 95]
a[3] = [5, 6]		#[1, 'Stegosaurus', 6, [5, 6], 95]
a[6] = 99		#[1, 'Stegosaurus', 6, [5, 6], 95. nil, 99]

Si el índice de la asignación []= son dos números(un inicio y longitud) o un rango, los dos elementos en el array original son reemplazados por lo que haya a la derecha de la asignación.

a = [1, 5, 6, 38, 95]
a[2,2] = 'Velociraptor'	#[1, 5, 'Velociraptor', 95]
#Si la longitud es 0, se inserta el valor de la derecha antes de la posición de inicio
a[2,0] = 'Nintendo 64'	#[1, 5, 'Nintendo 64', 'Velociraptor', 95]
#Si el valor a asignar es un array, se usan sus elementos en la asignación
a[1,1] = [4, 7, 82]	#[1, 4, 7, 82, 'Nintendo 64', 'Velociraptor', 95]
a[0..3] = []		#['Nintendo 64', 'Velociraptor', 95]
a[5..6] = 'AYBABTU', 98	#['Nintendo 64', 'Velociraptor', 95, nil, nil, 'AYBABTU',  98]

Arrays como pilas y colas

Los arrays implementan las funciones push y pop que agregan y quitan elementos al final del array, por lo que pueden ser usados como pilas (stack):

pila = []
pila.push "Leonardo"
pila.push "Donatello"
pila.push "Raphael"
pila.push "Michelangelo"
 
puts pila.pop	# Michelangelo
puts pila.pop	# Raphael
p pila		# ["Leonardo", "Donatello"]

Los métodos shift y unshift agregan y quitan elementos del principio del Array. Combinando ambos obtenemos una cola FIFO:

cola = []
cola.push "Leonardo"
cola.push "Donatello"
puts cola.shift
puts cola.shift

En este código, los elementos se quitan del array en el orden que fueron insertados. Está bueno ir escribiendo todo esto en el shell interactivo de Ruby (irb), el cual debería estar instalado en su sistema si instalaron Ruby. De esa forma pueden ir comprobando los resultados esperados de cada método y demás.

Otra opción es usar los métodos first y last. Éstos devuelven los elementos pero sin quitarlos del array. Se puede pasar como parámetro la cantidad de elementos que queremos recibir.

Más info:

Feed de comentarios | Url para Trackbacks | Suscribirse a los posts por correo electrónico

15 comentarios en este post

  1. Avatar Deleteman 21 septiembre. 2011 - 11:16 am Firefox 6.0.2 GNU/Linux 64 bits

    Muy bueno el articulo, cubre la base de los arrays muy bien!

    Un pique sobre arrays (que va de la mano con la asignación en paralelo) es que podés separar un array en head y tail (“ala” programación funcional) bien fácil, haciendo (por lo menos en ruby 1.9.2):

    head, *tail = [1,2,3,4,5]

    Te queda head = 1 y tail = [2,3,4,5], así podés hacer cosas como:

    def sum list
      head, *tail = list
      s = (tail.count == 0)?head:(head + sum(tail))
    end

    Y ahí podés llamar a, por ejemplo: sum (1..1000).to_a y te hace la suma super rápido.

    Da para chiviar un poco con recursión 🙂

    • Avatar Fernando 22 septiembre. 2011 - 10:27 am Firefox 6.0.2 GNU/Linux 64 bits

      ¡Gracias por el comentario! Modifiqué un poco el comentario para darle formato (acá hay más info de cómo hacerlo).

      Voy a jugar un rato con el código que aportaste, ¡gracias por el pique! Es el tipo de aportes que busco con estos posts 🙂

  2. Avatar Liber Dovat 21 septiembre. 2011 - 11:55 am Google Chrome 13.0.782.220 GNU/Linux 64 bits

    Muy bueno el tutorial!!

    Ahora, una duda.

    En el ejemplo de a = [3.141592, “pi”, 42] decís que a[3] vale 42, pero no sería a[2]?
    Pregunto porque en realidad no sé como funciona ruby 🙂

  3. Avatar M 27 septiembre. 2011 - 11:38 pm Firefox 5.0 Windows 7

    Muy bueno!!

    Che podrías hacerte unos tutoriales de Android también no? 😛

    • Avatar Fernando 28 septiembre. 2011 - 7:56 pm Firefox 7.0 GNU/Linux 64 bits

      ¡Gracias!

      No he tocado Android en un buen tiempo, pero no estaría mal armar algo. Tengo ganas de probar algo en Android. Por ahora vengo estudiando intensivamente Ruby, pero ni bien meta mano en Android nuevamente, ¡lo publico!

      Saludos

  4. Avatar Fabian Astorgan 24 diciembre. 2012 - 12:37 pm Firefox 17.0 GNU/Linux 64 bits

    Hola, estoy empezando en ruby..te hago una consulta a ver sime podes dar una mano.
    Necesito leer un archivo de texto y asignar cada linea a una variable distinta. Tengo una forma de resolver, pero es poco ortodoxa y ya que estoy aprendiendo quiero hacerlo bien.. mi idea (la que no funciona) seria asi:
    el con tenido del archivo supongamos:

    JUAN
    PEDRO
    PABLO

    File.read(archivo).each_line { | line | #leo el archivo
    vector = [“#{archive}”,”#{archive}”,”#{archive}”]# esta es la parte que no se.. la idea seria asignar cada linea en una matriz

    @variable1 = vector[0] # juan
    @variable2 = vector[1] # pedro

    No se si estoy mezclando peras con pepinos.. si mepodes dar una mano te lo agradesco.. Saludos

    • Avatar Fernando 25 mayo. 2013 - 6:25 am Firefox 23.0 Ubuntu 64 bits

      Fabian,
      Si entendí bien la pregunta, la cosa sería así:

      fernando@endor ~/ $ pry
      [1] pry(main)> vector = []
      []
      [2] pry(main)> File.read("./archivo").each_line do |line|
      [2] pry(main)*   vector << line #Asi agregas la línea al array
      [2] pry(main)* end
      "JUANnPEDROnPABLOn"
      [3] pry(main)> puts vector.inspect
      ["JUANn", "PEDROn", "PABLOn"]
      nil
      [4] pry(main)> puts vector[0]
      JUAN
      nil
      [5] pry(main)> puts vector[1]
      PEDRO
      nil
      [6] pry(main)>
  5. Avatar Fabian Astorgan 24 diciembre. 2012 - 12:38 pm Firefox 17.0 GNU/Linux 64 bits

    Perdon, en vector donde dice “#{archive}” deberia ser “#{line}” je

  6. Avatar Matias 21 julio. 2015 - 3:30 pm Google Chrome 43.0.2357.134 Windows 7

    como agregar varios datos en una matriz despues de un enter, se entiende??

    EJ: Yo quiero agregar una palabra, y al rato quiero agregar otra palabra y despues se me ocurre agregar otra palabra…. Esto tendria que ser en lineas diferentes y interactuando con el programa.

    En teoria los datos que uno agrega tiene que estar guardados en la matriz y si yo llamo a esa matriz tiene que devolver los datos que se guardaron!!!

    • Avatar Fernando 21 julio. 2015 - 7:08 pm Firefox 41.0 GNU/Linux 64 bits

      Hola Matías,
      Para agregar elementos a una matriz hay que usar el operador < < o push. Ejemplo:

      2.2.2 :001 > matriz = []
       => []
      2.2.2 :002 > matriz << "Palabra"
       => ["Palabra"]
      2.2.2 :003 > matriz << "Otra Palabra"
       => ["Palabra", "Otra Palabra"]
      2.2.2 :004 > matriz.push "Tercera"
       => ["Palabra", "Otra Palabra", "Tercera"]
      2.2.2 :005 > matriz
       => ["Palabra", "Otra Palabra", "Tercera"]

      Capaz que debería agregarlo al post si no quedó muy claro. ¡Saludos!

  7. Avatar Ale 14 abril. 2016 - 9:24 am Firefox 45.0 Ubuntu 64 bits

    Hola. Si tengo un array de cinco posiciones Ejemplo. a [1,2,3,4,5] quiero eliminar la posicion 3. Como lo haria?
    Gracias

    • Avatar Fernando 28 abril. 2016 - 1:43 pm Firefox 45.0 GNU/Linux 64 bits

      Hola Ale,
      Para eliminar el elemento de una posición se puede usar el método delete_at:

      a = [1, 2, 3, 4, 5]
       => [1, 2, 3, 4, 5]
      a.delete_at(3)
       => 4
      a
       => [1, 2, 3, 5]

    Dejar un comentario

    Toasty!