Mundo Maker
¡Bienvenid@ a Mundo Maker!

¿Quieres aprender todo sobre el RPG Maker?



Regístrate y forma parte de Mundo Maker.

[RMXP/VX] [Herramienta de scripter] Array +

Ver el tema anterior Ver el tema siguiente Ir abajo

[RMXP/VX] [Herramienta de scripter] Array +

Mensaje por Wecoc el Vie 14 Dic 2012 - 18:58

Hice algunas cosas más a la class Array de siempre para que los scripters podais usarla más plenamente.
Si lo usais en vuestros scripts no hace falta que me deis créditos.
Sé que no soy un scripter demasiado guay y habrá mejores maneras de hacer las cosas, pero hice lo que pude xDD

Versión 1.0 (vieja):
Código:
#==============================================================================
# ** [Herramienta de scripter] Array +
#------------------------------------------------------------------------------
#  Nuevas funciones para la class Array
#  by: Wecoc (no hace falta dar créditos)
#==============================================================================

class Array
  #--------------------------------------------------------------------------
  # suma (nueva)
  #--------------------------------------------------------------------------
  # Con la suma normal: [2,4]+[1,2] #=> [2,4,1,2]
  # Array.suma([2,4],[1,2]) #=> [3,6]
  # Nota: Se pueden sumar muchas array a la vez.
  #--------------------------------------------------------------------------
  def self.suma_2(a,b)
    c = []
    loop do
      if a.length != b.length
        if a.length < b.length
          a.insert a.length, 0
        else
          b.insert b.length, 0
        end
      else
        break
      end
    end
    for i in 0...a.length
      c[i] = a[i] + b[i]
    end
    return c
  end
  def self.suma(*args)
    if args.length == 1
      return args[0]
    elsif args.length == 2
      return self.suma_2(args[0],args[1])
    end
    return Array.suma_2(args.pop, Array.suma(args))
  end
  
  #--------------------------------------------------------------------------
  # resta (nueva)
  #--------------------------------------------------------------------------
  # Con la resta normal: [2,4]-[1,2] #=> [4]
  # Array.resta([2,4],[1,2]) #=> [1,2]
  # Nota: Se pueden restas muchas array a la vez.
  #--------------------------------------------------------------------------
  def self.resta_2(a,b)
    c = []
    loop do
      if a.length != b.length
        if a.length < b.length
          a.insert a.length, 0
        else
          b.insert b.length, 0
        end
      else
        break
      end
    end
    for i in 0...a.length
      c[i] = a[i] - b[i]
    end
    return c
  end
  def self.resta(*args)
    if args.length == 1
      return args[0]
    elsif args.length == 2
      return self.resta_2(args[0],args[1])
    end
    return Array.resta_2(args.pop, Array.suma(args))
  end
  
  # Comparadores
  def <(otro)
    (self <=> otro) == -1
  end
  # ------------------------------------
  def <=(otro)
    (self < otro) or (self == otro)
  end
  # ------------------------------------
  def >(otro)
    (self <=> otro) == 1
  end
  # ------------------------------------
  def >=(otro)
    (self > otro) or (self == otro)
  end
  
  #--------------------------------------------------------------------------
  # sort_by # Este no lo escribí yo D:
  #--------------------------------------------------------------------------
  # Sirve para poder ordenar cualquier data según un parámetro concreto
  # Ejemplo: En Window_Item para poder ordenar los objetos por:
  # # id --> @data.sort_by(:id)
  # # nombre --> @data.sort_by(:name)
  # # precio --> @data.sort_by(:price)
  #--------------------------------------------------------------------------
  def sort_by(sym)
    self.sort {|x,y| x.send(sym) <=> y.send(sym) }
  end
  def sort_by!(sym)
    self.sort! {|x,y| x.send(sym) <=> y.send(sym) }
  end
 
  #--------------------------------------------------------------------------
  # subset?(other) / superset?(other)
  #--------------------------------------------------------------------------
  # Comprueba si uno incluye al otro de forma similar al include
  # a = [1, 2, 3, 4]
  # b = [2, 3]
  # c = [2, 3, 4, 5]
  # flag1 = c.subset? a     # false
  # flag2 = b.subset? a     # true
  # flag3 = c.superset? b   # true
  #--------------------------------------------------------------------------
  def subset?(other)
    self.each  do |x|
      if !(other.include? x)
        return false
      end
    end
    return true
  end
  def superset?(other)
    other.subset?(self)
  end
  
  #--------------------------------------------------------------------------
  # powerset # Este no lo escribí yo D:
  #--------------------------------------------------------------------------
  # Busca todas las combinaciones posibles entre los elementos de una array.
  # Nota: no confundir combinación con permutación
  # x = [1, 2, 3]
  # y = x.powerset #=> [[], [1], [2], [1,2], [3], [1,3], [2,3], [1,2,3]]
  #--------------------------------------------------------------------------
  def powerset
    num = 2**size
    ps = Array.new(num, [])
    self.each_index do |i|
      a = 2**i
      b = 2**(i+1) - 1
      j = 0
      while j < num-1
        for j in j+a..j+b
          ps[j] += [self[i]]
        end
        j += 1
      end
    end
    ps
  end

  #--------------------------------------------------------------------------
  # combination
  #--------------------------------------------------------------------------
  # Hace un powerset pero con solo los resultados de tamaño n.
  # En otras palabras, hace la combinación entre los argumentos de la array.
  # Nota: Esta clase forma parte de Ruby pero no de RGSS por eso la reescribí :3
  # x = [1, 2, 3]
  # y = x.combination(1) #=> [[1], [2], [3]]
  # y = x.combination(2) #=> [[1,2], [1,3], [2,3]]
  # y = x.combination(3) #=> [[1,2,3]]
  #--------------------------------------------------------------------------
  def combination(n)
    result = []
    power = self.powerset
    return if n > power.length
    return [[]] if n == 0
    for i in 0..power.length
      if power[i].to_a.length == n
        result.push power[i]
      end
    end
    return result
  end
  # Nota: Añadiendo y.flatten luego quitaría las arrays dentro de array.
  # y = [[1,2], [1,3], [2,3]]
  # y.flatten # [1,2,1,3,2,3]
    
  
  #--------------------------------------------------------------------------
  # product
  #--------------------------------------------------------------------------
  # Crea una array con las combinaciones entre sus números como si multiplicara
  # Esta clase forma parte de Ruby pero no de RGSS por eso la reescribí :3
  # pero solo parcialmente (más información en la siguiente nota)
  # [1,2,3].product_2([4,5]) #=> [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]
  #
  # [1,2].product([3,4],[5,6]) #=>[[1,3,5],[1,3,6],[1,4,5],[1,4,6],
                               #  [2,3,5],[2,3,6],[2,4,5],[2,4,6]]
  #--------------------------------------------------------------------------
  def product_2(array)
    a = result = []
    if array.is_a?(Numeric)
      for i in 0...self.length
        result[i] = self[i] * array
      end
      return result
    end
    return nil if array.length == 0
    if array.length == 1
      for i in 0...self.length
        result[i] = self[i] * array[0]
      end
      return result
    end
    for i in 0..self.length-1
      a = [self[i],array].flatten
      result += a.combination(array.length)
      result.pop
    end
    return result
  end
  
  def product(*args)
    result = []
    return nil if args.length == 0
    if args.length == 1
      return self.product_2(*args)
    end
    if args.length == 2
      resprev = self.product_2(args[0])
      for i in 0..resprev.length-1
        for j in 0..args[1].length-1
          result.push resprev[i]+args[1][j].to_a
        end
      end
      return result
    end
    # Nota: No lo he hecho para más de 2 argumentos porque era demasiado
    # complicado para mí.
  end
                              
  #--------------------------------------------------------------------------
  # count # Este no lo escribí yo D:
  #--------------------------------------------------------------------------
  # a cada valor cuenta cuantas veces sale
  #--------------------------------------------------------------------------
  def count
    k=Hash.new(0)
    self.each{|x| k[x]+=1 }
    k
  end
      
  #--------------------------------------------------------------------------
  # invert
  #--------------------------------------------------------------------------
  # Esta clase forma parte de Ruby pero no de RGSS (que yo sepa xD)
  # ["a","b","c","d"].invert #=> ["d","c","b","a"]
  #--------------------------------------------------------------------------
  def invert
    a = []
    for i in 0..self.length-1
      a[i] = self[self.length-1-i]
    end
    return a
  end
  
  #--------------------------------------------------------------------------
  # rotate
  #--------------------------------------------------------------------------
  # Rota los valores de las arrays.
  # Esta clase forma parte de Ruby pero no de RGSS por eso la reescribí :3
  # ["a","b","c","d"].rotate #=> ["b","c","d","a"]
  # ["a","b","c","d"].rotate(-2) #=> ["c","d","a","b"]
  #--------------------------------------------------------------------------
  def rotate(n=1)
    return self if n == 0
    c = []
    if n == 1
      for i in 0..self.length-1
        c[i] = self[0]
        c[i-1] = self[i]
      end
      return c
    end
    if n > 1
      a = self.rotate
      for i in 1..n-1
        a = a.rotate
      end
      return a
    end
    if n == -1
      a = self.invert.rotate.invert
      return a
    end
    if n < -1
      a = self.invert
      for i in 0..(-n)-1
        a = a.rotate
      end
      a = a.invert
      return a
    end
  end
  
  #--------------------------------------------------------------------------
  # take
  #--------------------------------------------------------------------------
  # Crea una nueva array con los n primeros valores de la array inicial
  # Esta clase forma parte de Ruby pero no de RGSS por eso la reescribí :3
  # a = [1,2,3,4,5]
  # a.take(3) #=> [1,2,3]
  #--------------------------------------------------------------------------
  def take(n)
    return self if n > self.length
    a = []
    for i in 0...n
      a.push self[i]
    end
    return a
  end

  #--------------------------------------------------------------------------
  # transpose
  #--------------------------------------------------------------------------
  # Asume la array inicial como una array de arrays y cambia cada valor por su i
  # (Hace la "matriz" transpuesta)
  # Esta clase forma parte de Ruby pero no de RGSS por eso la reescribí :3
  # a = [[1,2], [3,4], [5,6]]
  # a.transpose   #=> [[1, 3, 5], [2, 4, 6]]
  #--------------------------------------------------------------------------
  def transpose
    array = self.dup
    array.compact!
    n = array.length
    for i in 0...n
      if array[i].length == 1
        return nil
      end
    end
    m = array[0].length
    result = []
    for i in 0..m-1
      result.push [array[0][i]]
      for j in 1...n
        result[i].push array[j][i]
      end
    end
    return result
  end

  #--------------------------------------------------------------------------
  # zip
  #--------------------------------------------------------------------------
  # Funciona como una transpuesta pero usando diferentes array para contruir la
  # matriz la cual usará para hacer la transpuesta.
  # Esta clase forma parte de Ruby pero no de RGSS por eso la reescribí :3
  #--------------------------------------------------------------------------
  # a = [4, 5, 6]
  # b = [7, 8, 9]
  # [1,2,3].zip(a, b)      #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
  # [1,2].zip(a,b)         #=> [[1, 4, 7], [2, 5, 8]]
  #--------------------------------------------------------------------------
  def zip(*args)
    a = [self.dup]
    for i in 0..args.length-1
      a.push args[i]
    end
    return a.transpose
  end
  #--------------------------------------------------------------------------
  # USO ESPECIAL DE ZIP (sacado de internet):
  # name = ['a', 'b', 'c']
  # how_many_of_each = [3, 5, 2]
  # name.zip(how_many_of_each).collect {|n, hm| [n] *hm }
  # => ["a", "a", "a", "b", "b", "b", "b", "b", "c", "c"]
  #--------------------------------------------------------------------------


  #--------------------------------------------------------------------------
  # Rotacion X
  #--------------------------------------------------------------------------
  # Hace una rotación matemática sobre el eje X de la array tomada como un vector,
  # siempre y cuando tenga 3 componentes.
  #--------------------------------------------------------------------------
  def rotation_x(angle)
    array = self
    if array.length == 3
      a0 = array[0]
      a1 = -array[2]*Math.sin(angle)+array[1]*Math.cos(angle)
      a2 = array[2]*Math.cos(angle)+array[1]*Math.sin(angle)
      return [a0,a1,a2]
    else
      return nil
    end
  end
  
  #--------------------------------------------------------------------------
  # Rotacion Y
  #--------------------------------------------------------------------------
  # Hace una rotación matemática sobre el eje Y de la array tomada como un vector,
  # siempre y cuando tenga 3 componentes.
  #--------------------------------------------------------------------------
  def rotation_y(angle)
    array = self
    if array.length == 3
      a0 = array[2]*Math.sin(angle)+array[0]*Math.cos(angle)
      a1 = array[1]
      a2 = array[2]*Math.cos(angle)-array[0]*Math.sin(angle)
      return [a0,a1,a2]
    else
      return nil
    end
  end
  
  #--------------------------------------------------------------------------
  # Rotacion Z
  #--------------------------------------------------------------------------
  # Hace una rotación matemática sobre el eje Z de la array tomada como un vector,
  # siempre y cuando tenga 3 componentes.
  #--------------------------------------------------------------------------
  def rotation_z(angle)
    array = self
    if array.length == 3
      a0 = -array[1]*Math.sin(angle)+array[0]*Math.cos(angle)
      a1 = array[1]*Math.cos(angle)+array[0]*Math.sin(angle)
      a2 = array[2]
      return [a0,a1,a2]
    else
      return nil
    end
  end
end

Aquí una lista de las cosas nuevas que trae este tool:

- suma (nueva)
- resta (nueva)
- (comparadores)
- sort_by
- subset? || superset?
- powerset
- combination
- product
- count
- invert
- rotate
- take
- transpose
- zip
- rotation_x || rotation_y || rotation_z

La versión más reciente es la 1.2, que podéis encontrar en éste mismo topic.

Es para RPG maker XP, pero al ser una clase oculta en gran parte también funciona en RPG maker VX y Ace. Algunos de los métodos pueden usarse por separado, pero vigilad en el código que no usen otros métodos del propio Array+ de modo interno.


Última edición por Wecoc el Miér 24 Ene 2018 - 23:58, editado 3 veces
avatar
Wecoc
Administrador
Administrador



Créditos 12290

Gracias : 564

Volver arriba Ir abajo

Re: [RMXP/VX] [Herramienta de scripter] Array +

Mensaje por luistop12 el Vie 14 Dic 2012 - 19:04

No sé que coño es pero se agradece el aporte bro ^-^
avatar
luistop12
Veterano
Veterano

0/3

Créditos 770

Gracias : 30

Volver arriba Ir abajo

Re: [RMXP/VX] [Herramienta de scripter] Array +

Mensaje por silvanash el Vie 14 Dic 2012 - 19:13

ORZ!! ¡Más funciones para los arrays! Tenía pensado parir algún script aprovechando los arrays, pero esto mejora en mucho lo que se puede hacer con ellos. Ya sólo con poder sumar y restar arrays se me vienen a la cabeza muchas ideas.

¡Dale duro!
avatar
silvanash
Aventurero
Aventurero

0/3

Créditos 1628

Gracias : 230

Volver arriba Ir abajo

Re: [RMXP/VX] [Herramienta de scripter] Array +

Mensaje por newold el Vie 14 Dic 2012 - 21:44

No entiendo muy bien para que son los métodos rotate. Cada uno entrega un array de 3 valores

Cojo un array de 3 valores, por ejemplo, [100,100,100] y al calcular en un rango de 0 a 360 usando los métodos rotation_x(angle) para calcular la X y rotation_y(angle) para calcular la Y sale algo como esto:



Así que, cual es la funcion real de los métodos rotation_x y rotation_y??

y el rotation_z (este no he sacado nada de él xD)

y en cuanto a la suma de arrays, para que se puede usar eso? no se me ocurre ninguna utilidad.

de paso dejo también otro método que no está en la lista (sirve para convertir un array a hash)

Código:
class Array
  def to_hash # << by NEWOLD
    hash = {}
    for i in 0...self.size
      hash[i] = self[i]
    end
    return hash
  end
end
avatar
newold
Principiante
Principiante

0/3

Créditos 1112

Gracias : 78

Volver arriba Ir abajo

Re: [RMXP/VX] [Herramienta de scripter] Array +

Mensaje por Wecoc el Vie 14 Dic 2012 - 22:04

Gracias por el to_hash
Hay muchas más cosas que se podrían añadir en la class Array aún xD

La verdad, no hice lo de la suma pensando en una utilidad en concreto, es solo que me pareció "rara" la suma por defecto de las arrays, y quise hacerle esta variación de suma y resta más propiamente vectoriales, por si se necesitara en algún momento dado.

Lo de la rotación también sería darle a la Array un aspecto más de vector que de propia array. Aún así, lo único que hace es aplicarle una matriz de rotación en tres dimensiones, cosa que raramente se le podrá dar utilidad, ya lo sé.

En Wikipedia se escribió:En álgebra lineal, una matriz de rotación es la matriz que representa una rotación en el espacio euclídeo. Por ejemplo, la matriz



representa la rotación de θ grados del plano en sentido antihorario. En tres dimensiones, las matrices de rotación representan las rotaciones de manera concisa y se usan frecuentemente en geometría, física e informática.

Simplemente aplica esas tres matrices de rotación a la array.
PD.- Buen experimento el tuyo xD fíjate que son 3 circumferencias en ejes distintos.

Las demás cosas son más útiles, además de algunas formar parte del Ruby.
avatar
Wecoc
Administrador
Administrador



Créditos 12290

Gracias : 564

Volver arriba Ir abajo

Re: [RMXP/VX] [Herramienta de scripter] Array +

Mensaje por Eron el Lun 22 Abr 2013 - 10:46

Versión 1.1 (vieja):
Código:
#==============================================================================
# ** [Herramienta de scripter] Array+ version 1.1
#------------------------------------------------------------------------------
#  Nuevas funciones para la class Array
#  by: Wecoc, Newold & Eron (no hace falta dar créditos)
#==============================================================================

class Array
 
 # /////////////////////////////////////////////////////////////////
  # ///////////////////// Aritmética I (Wecoc) //////////////////////
  # /////////////////////////////////////////////////////////////////
 
 #--------------------------------------------------------------------------
  # suma (nueva)
  #--------------------------------------------------------------------------
  # Con la suma normal: [2,4]+[1,2] #=> [2,4,1,2]
  # Array.suma([2,4],[1,2]) #=> [3,6]
  # Nota: Se pueden sumar muchas array a la vez.
  #--------------------------------------------------------------------------
  def self.suma_2(a,b)
    c = []
    loop do
      if a.length != b.length
        if a.length < b.length
          a.insert a.length, 0
        else
          b.insert b.length, 0
        end
      else
        break
      end
    end
    for i in 0...a.length
      c[i] = a[i] + b[i]
    end
    return c
  end
  def self.suma(*args)
    if args.length == 1
      return args[0]
    elsif args.length == 2
      return self.suma_2(args[0],args[1])
    end
    return Array.suma_2(args.pop, Array.suma(args))
  end
 
 #--------------------------------------------------------------------------
  # resta (nueva)
  #--------------------------------------------------------------------------
  # Con la resta normal: [2,4]-[1,2] #=> [4]
  # Array.resta([2,4],[1,2]) #=> [1,2]
  # Nota: Se pueden restas muchas array a la vez.
  #--------------------------------------------------------------------------
  def self.resta_2(a,b)
    c = []
    loop do
      if a.length != b.length
        if a.length < b.length
          a.insert a.length, 0
        else
          b.insert b.length, 0
        end
      else
        break
      end
    end
    for i in 0...a.length
      c[i] = a[i] - b[i]
    end
    return c
  end
  def self.resta(*args)
    if args.length == 1
      return args[0]
    elsif args.length == 2
      return self.resta_2(args[0],args[1])
    end
    return Array.resta_2(args.pop, Array.suma(args))
  end
 
 # /////////////////////////////////////////////////////////////////
  # ///////////////////// Comparadores (Wecoc) //////////////////////
  # /////////////////////////////////////////////////////////////////
 
 def <(otro)
    (self <=> otro) == -1
  end
  # ------------------------------------
  def <=(otro)
    (self < otro) or (self == otro)
  end
  # ------------------------------------
  def >(otro)
    (self <=> otro) == 1
  end
  # ------------------------------------
  def >=(otro)
    (self > otro) or (self == otro)
  end
 
 # /////////////////////////////////////////////////////////////////
  # ////////////////////// Ordenación (Wecoc) ///////////////////////
  # /////////////////////////////////////////////////////////////////

  #--------------------------------------------------------------------------
  # sort_by
  #--------------------------------------------------------------------------
  # Sirve para poder ordenar cualquier data según un parámetro concreto
  # Ejemplo: En Window_Item para poder ordenar los objetos por:
  # # id --> @data.sort_by(:id)
  # # nombre --> @data.sort_by(:name)
  # # precio --> @data.sort_by(:price)
  #--------------------------------------------------------------------------
  def sort_by(sym)
    self.sort {|x,y| x.send(sym) <=> y.send(sym) }
  end
  
  def sort_by!(sym)
    self.sort! {|x,y| x.send(sym) <=> y.send(sym) }
  end
 
 #--------------------------------------------------------------------------
  # max_by
  #--------------------------------------------------------------------------
  # Sirve para poder obtener el mayor valor de la array según un parámetro
  # concreto, su funcionamiento es igual que el sort_by
  #--------------------------------------------------------------------------
  def max_by(sym)
    self.max {|x,y| x.send(sym) <=> y.send(sym) }
  end
    
  #--------------------------------------------------------------------------
  # min_by
  #--------------------------------------------------------------------------
  # Sirve para poder obtener el menor valor de la array según un parámetro
  # concreto, su funcionamiento es igual que el sort_by
  #--------------------------------------------------------------------------
  def min_by(sym)
    self.min {|x,y| x.send(sym) <=> y.send(sym) }
  end

  # Combinatoria (Wecoc)

 
 #--------------------------------------------------------------------------
  # subset?(other) / superset?(other)
  #--------------------------------------------------------------------------
  # Comprueba si uno incluye al otro de forma similar al include
  # a = [1, 2, 3, 4]
  # b = [2, 3]
  # c = [2, 3, 4, 5]
  # flag1 = c.subset? a    # false
  # flag2 = b.subset? a    # true
  # flag3 = c.superset? b  # true
  #--------------------------------------------------------------------------
  def subset?(other)
    self.each  do |x|
      if !(other.include? x)
        return false
      end
    end
    return true
  end
  
  def superset?(other)
    other.subset?(self)
  end
 
 #--------------------------------------------------------------------------
  # powerset # Este no lo escribí yo D:
  #--------------------------------------------------------------------------
  # Busca todas las combinaciones posibles entre los elementos de una array.
  # Nota: no confundir combinación con permutación
  # x = [1, 2, 3]
  # y = x.powerset #=> [[], [1], [2], [1,2], [3], [1,3], [2,3], [1,2,3]]
  #--------------------------------------------------------------------------
  def powerset
    num = 2**size
    ps = Array.new(num, [])
    self.each_index do |i|
      a = 2**i
      b = 2**(i+1) - 1
      j = 0
      while j < num-1
        for j in j+a..j+b
          ps[j] += [self[i]]
        end
        j += 1
      end
    end
    ps
  end

  #--------------------------------------------------------------------------
  # combination
  #--------------------------------------------------------------------------
  # Hace un powerset pero con solo los resultados de tamaño n.
  # En otras palabras, hace la combinación entre los argumentos de la array.
  # Nota: Esta clase forma parte de Ruby pero no de RGSS por eso la reescribí :3
  # x = [1, 2, 3]
  # y = x.combination(1) #=> [[1], [2], [3]]
  # y = x.combination(2) #=> [[1,2], [1,3], [2,3]]
  # y = x.combination(3) #=> [[1,2,3]]
  #--------------------------------------------------------------------------
  def combination(n)
    result = []
    power = self.powerset
    return if n > power.length
    return [[]] if n == 0
    for i in 0..power.length
      if power[i].to_a.length == n
        result.push power[i]
      end
    end
    return result
  end
  # Nota: Añadiendo y.flatten luego quitaría las arrays dentro de array.
  # y = [[1,2], [1,3], [2,3]]
  # y.flatten # [1,2,1,3,2,3]
  #--------------------------------------------------------------------------
  def sample(n=1)
    array = self.clone.compact
    result = []
    for i in 0...n
      random = rand(array.size)
      result.push(array[random])
      array.delete_at(random)
    end
    return result
  end


 # /////////////////////////////////////////////////////////////////
  # ///////////////////// Aritmética II (Wecoc) //////////////////////
  # /////////////////////////////////////////////////////////////////

 
 #--------------------------------------------------------------------------
  # product
  #--------------------------------------------------------------------------
  # Crea una array con las combinaciones entre sus números como si multiplicara
  # Esta clase forma parte de Ruby pero no de RGSS por eso la reescribí :3
  # pero solo parcialmente (más información en la siguiente nota)
  # [1,2,3].product_2([4,5]) #=> [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]
  #
  # [1,2].product([3,4],[5,6]) #=>[[1,3,5],[1,3,6],[1,4,5],[1,4,6],
                              #  [2,3,5],[2,3,6],[2,4,5],[2,4,6]]
  #--------------------------------------------------------------------------
  def product_2(array)
    a = result = []
    if array.is_a?(Numeric)
      for i in 0...self.length
        result[i] = self[i] * array
      end
      return result
    end
    return nil if array.length == 0
    if array.length == 1
      for i in 0...self.length
        result[i] = self[i] * array[0]
      end
      return result
    end
    for i in 0..self.length-1
      a = [self[i],array].flatten
      result += a.combination(array.length)
      result.pop
    end
    return result
  end
 
 def product(*args)
    result = []
    return nil if args.length == 0
    if args.length == 1
      return self.product_2(*args)
    end
    if args.length == 2
      resprev = self.product_2(args[0])
      for i in 0..resprev.length-1
        for j in 0..args[1].length-1
          result.push resprev[i]+args[1][j].to_a
        end
      end
      return result
    end
    # Nota: No lo he hecho para más de 2 argumentos porque era demasiado
    # complicado para mí.
  end
                
 # /////////////////////////////////////////////////////////////////
  # ///////////////////////// Otros (Wecoc) /////////////////////////
  # /////////////////////////////////////////////////////////////////


  #--------------------------------------------------------------------------
  # count
  #--------------------------------------------------------------------------
  # a cada valor cuenta cuantas veces sale
  #--------------------------------------------------------------------------
  def count
    k=Hash.new(0)
    self.each{|x| k[x]+=1 }
    k
  end
 
 #--------------------------------------------------------------------------
  # invert
  #--------------------------------------------------------------------------
  # Esta clase forma parte de Ruby pero no de RGSS (que yo sepa xD)
  # ["a","b","c","d"].invert #=> ["d","c","b","a"]
  #--------------------------------------------------------------------------
  def invert
    a = []
    for i in 0..self.length-1
      a[i] = self[self.length-1-i]
    end
    return a
  end
 

 #--------------------------------------------------------------------------
  # after
  #--------------------------------------------------------------------------
  # array = ["Hola", "Eron", "Mundo", "Wecoc", "Newold"]
  # array.after("Hola") #=> "Eron"
  # array.after("Hola",3) #=> "Wecoc"
  # array.after("Wecoc",-1) #=> "Mundo"
  #--------------------------------------------------------------------------
  def after(val,num=1)
    if self.include?(val)
      a = self.index(val)
      return self[a + num]
    else
      return nil
    end
  end

  #--------------------------------------------------------------------------
  # rotate
  #--------------------------------------------------------------------------
  # Rota los valores de las arrays.
  # Esta clase forma parte de Ruby pero no de RGSS por eso la reescribí :3
  # ["a","b","c","d"].rotate #=> ["b","c","d","a"]
  # ["a","b","c","d"].rotate(-2) #=> ["c","d","a","b"]
  #--------------------------------------------------------------------------
  def rotate(n=1)
    return self if n == 0
    c = []
    if n == 1
      for i in 0..self.length-1
        c[i] = self[0]
        c[i-1] = self[i]
      end
      return c
    end
    if n > 1
      a = self.rotate
      for i in 1..n-1
        a = a.rotate
      end
      return a
    end
    if n == -1
      a = self.invert.rotate.invert
      return a
    end
    if n < -1
      a = self.invert
      for i in 0..(-n)-1
        a = a.rotate
      end
      a = a.invert
      return a
    end
  end
 
 #--------------------------------------------------------------------------
  # take
  #--------------------------------------------------------------------------
  # Crea una nueva array con los n primeros valores de la array inicial
  # Esta clase forma parte de Ruby pero no de RGSS por eso la reescribí :3
  # a = [1,2,3,4,5]
  # a.take(3) #=> [1,2,3]
  #--------------------------------------------------------------------------
  def take(n)
    return self if n > self.length
    a = []
    for i in 0...n
      a.push self[i]
    end
    return a
  end
  
  #--------------------------------------------------------------------------
  # zip
  #--------------------------------------------------------------------------
  # Funciona como una transpuesta pero usando diferentes array para contruir la
  # matriz la cual usará para hacer la transpuesta.
  # Esta clase forma parte de Ruby pero no de RGSS por eso la reescribí :3
  #--------------------------------------------------------------------------
  # a = [4, 5, 6]
  # b = [7, 8, 9]
  # [1,2,3].zip(a, b)      #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
  # [1,2].zip(a,b)        #=> [[1, 4, 7], [2, 5, 8]]
  #--------------------------------------------------------------------------
  def zip(*args)
    a = [self.dup]
    for i in 0..args.length-1
      a.push args[i]
    end
    return a.transpose
  end
  #--------------------------------------------------------------------------
  # USO ESPECIAL DE ZIP (sacado de internet):
  # name = ['a', 'b', 'c']
  # how_many_of_each = [3, 5, 2]
  # name.zip(how_many_of_each).collect {|n, hm| [n] *hm }
  # => ["a", "a", "a", "b", "b", "b", "b", "b", "c", "c"]
  #--------------------------------------------------------------------------
 
 #--------------------------------------------------------------------------
  # strip_values_at!
  #--------------------------------------------------------------------------
  # Devuelve los valores de las posiciones que digas de la array.
  # a = [0, "a", 4, 3]
  # p a.strip_values_at!(1, 2) # ["a", 4]
  #--------------------------------------------------------------------------
  
  def strip_values_at!(*args)
    args.each do |x|
      values = []
      dummy = Object.new
      args.each do |i|
        if i < size
          values << self[i]
          self[i] = dummy
        end
      end
      delete(dummy)
      return values
    end
  end

  #--------------------------------------------------------------------------
  # extract!
  #--------------------------------------------------------------------------
  # Quita los valores que le digas de la array.
  # a = ("a".."h").to_a # => ["a", "b", "c", "d", "e", "f", "g", "h"]
  # p a.extract! { |x| x < "e" && x != "b" }     # => ["a", "c", "d"]
  #--------------------------------------------------------------------------

  def extract!
    ary = self.dup
    self.reject! { |x| yield x }
    ary - self
  end
  
  # /////////////////////////////////////////////////////////////////
  # //////////////////// Array to Hash (NEWOLD) /////////////////////
  # /////////////////////////////////////////////////////////////////

 
 def to_hash
    hash = {}
    for i in 0...self.size
      hash[i] = self[i]
    end
    return hash
  end
 
 def into_hash(h)
    unless size % 2 == 0
      raise StandardError, "Expected array with even number of elements"
    end
    0.step(size-1, 2) { |x| h[self[x]] = self[x+1] }
    h
  end
  
  def uniq_count
    hash = {}
    each do |e|
      hash[e] ||= 0
      hash[e] += 1
    end
    return hash
  end
 
 # /////////////////////////////////////////////////////////////////
  # ////////////////////// Estadística (Eron) ///////////////////////
  # /////////////////////////////////////////////////////////////////
 
 #--------------------------------------------------------------------------
  # average - Calcula la media aritmética de los valores de la array.
  # Corresponde a la suma de los valores dividida por el número de valores.
  # Puede aplicarse a toda la array o a solo un rango.
  #--------------------------------------------------------------------------
  def average(ini=0, endd=self.length-1)
    return 0 if self.length == 0
    ini = [ini, 0].max
    ini = [ini, self.length-1].min
    endd = [endd, self.length-1].min
    endd = [endd, ini+1].max
    a = 0.0
    for i in ini..endd
      a += self[i]
    end
    n = (endd-ini)+1.0
    return (a/n)
  end
 
 #--------------------------------------------------------------------------
  # geo_average - Calcula la media geométrica de los valores de la array.
  # Corresponde a la multiplicación de los valores elevada a (1 / nº de valores).
  # Puede aplicarse a toda la array o a solo un rango.
  #--------------------------------------------------------------------------
  def geo_average(ini=0, endd=self.length-1)
    return 0 if self.length == 0
    ini = [ini, 0].max
    ini = [ini, self.length-1].min
    endd = [endd, self.length-1].min
    endd = [endd, ini+1].max
   a = 1.0
    for i in ini..endd
      a *= self[i]
    end
    return a**(1/n)
  end
 
 #--------------------------------------------------------------------------
  # har_average - Calcula la media armónica de los valores de la array.
  # Corresponde a la inversa de la media aritmética de los inversos de los valores.
  # Puede aplicarse a toda la array o a solo un rango.
  #--------------------------------------------------------------------------
  def har_average(ini=0, endd=self.length-1)
    return 0 if self.length == 0
    ini = [ini, 0].max
    ini = [ini, self.length-1].min
    endd = [endd, self.length-1].min
    endd = [endd, ini+1].max
   a = 0.0
   for i in ini..endd
      return 0 if self[i] == 0
      a += (1/self[i].to_f)
    end
    n = (endd-ini)+1.0
    return (n/a)
  end
 
 #--------------------------------------------------------------------------
  # variance - Calcula la variancia según la definición inferencial.
  # Puede aplicarse a toda la array o a solo un rango.
  #--------------------------------------------------------------------------
  def variance(ini=0, endd=self.length-1)
    return 0 if self.length == 0
    ini = [ini, 0].max
    ini = [ini, self.length-1].min
    endd = [endd, self.length-1].min
    endd = [endd, ini+1].max
   aver = self.average(ini, endd)
    a = 0.0
    n = (endd-ini)+1.0
    for i in ini..endd
      a += ((self[i]-aver)**2)/(n-1.0)
    end
    return a
  end
 
 #--------------------------------------------------------------------------
  # stand_dev - Calcula la desviación estándar según la definición inferencial.
  # Eso equivale a la raíz de la variancia.
  # Puede aplicarse a toda la array o a solo un rango.
  #--------------------------------------------------------------------------
  def stand_dev(ini=0, endd=self.length-1)
    return Math.sqrt(self.variance(ini, endd))
  end
 
 #--------------------------------------------------------------------------
  # median - Devuelve la mediana de la array ordenada.
  # Puede aplicarse a toda la array o a solo un rango.
  #--------------------------------------------------------------------------
  def median(ini=0, endd=self.length-1)
    return 0 if self.length == 0
    ini = [ini, 0].max
    ini = [ini, self.length-1].min
    endd = [endd, self.length-1].min
    endd = [endd, ini+1].max    
   n = (endd-ini)+1.0
    if (n%2 == 1)
      return (self.sort[(n-1.0)/2.0]).to_f
    else
      return (self.sort[(n/2.0)-1.0]+self.sort[(n/2.0)])/2.0
    end
  end

  #--------------------------------------------------------------------------
  # covariance - Calcula la covariancia entre dos array del mismo tamaño.
  #--------------------------------------------------------------------------
  def self.covariance(a,b)
    n = [a.length, b.length].min
    avera = a.average(0,n)
    averb = b.average(0,n)
    m = 0.0
    for i in 0..(n-1)
      m += ((a[i]-avera)*(b[i]-averb))/(n-1)
    end
    return m
  end
 
 #--------------------------------------------------------------------------
  # correlation - Calcula la correlación entre dos array del mismo tamaño.
  #--------------------------------------------------------------------------
  def self.correlation(a,b)
    return self.covariance(a,b)/(a.stand_dev*b.stand_dev)
  end
 
end

Ya que Wecoc hizo esto he decidido añadir alguna cosa más. No parece muy útil pero quien sabe x'DDD Eso sí, quité las rotaciones x, y, z de Wecoc porque me parecieron una faltada. Pongo lo que hay ahora. Lo que puse yo corresponde a cálculos estadísticos, y luego añadí uniq_count que es el único que no hice yo. Funciona como el uniq_c, sea lo que sea eso. Lo puse con el hash porque usa hash xD!

- suma (nueva)
- resta (nueva)
- (comparadores)
- sort_by
- max_by
- min_by
- subset? || superset?
- powerset
- combination
- sample
- product
- count
- invert
- after
- rotate
- take
- zip
- strip_values_at!
- extract!

----------------
- to_hash
- into_hash
- uniq_count

----------------
- average
- geo_average
- har_average
- variance
- stand_dev
- median
- covariance
- correlation

Edito: No me había dado cuenta de que el tema era de diciembre.. espero que no pase nada, igualmente lo hice por aportar.

Que lo paséis bien con esto =DD!
avatar
Eron
Principiante
Principiante

0/3

Créditos 3599

Gracias : 60

Volver arriba Ir abajo

Re: [RMXP/VX] [Herramienta de scripter] Array +

Mensaje por Wecoc el Dom 30 Jun 2013 - 1:12

Veo también que pusiste un "after" raro xD Tal y como lo hiciste si hay alguna repetición en la array solo se detecta el primero... No es que sea mucho más útil que antes con tu mejora, la verdad es que no se me ocurre donde usar... nada... xDD pero te agradezco el esfuerzo.

¡Por cierto! Ya que hiciste la mediana, ¿no podrías hacer que midiera los percentiles?
Se me ocurrió que por ejemplo si se quisiera hacer una ordenación en tabla de una serie de objetos (hace tiempo que quiero hacer una Shop así xD) podría interesar adaptar el número de columnas y filas a un número óptimo. No se si sería necesario usar percentiles para eso, habría que pensarlo mejor... seguramente jugando con el total sea suficiente... pero quien sabe xD

=======================

Seguramente recordaréis que hace tiempo intenté hacer funcionar las array como si fueran matrices, aunque eso no tuviera demasiada utilidad. Bueno, hoy saqué un poco de tiempo para acabar eso y ahora ya es funcional, lo posteo aquí para que lo veáis.

Versión 1.0 (Vieja):
Código:
class Array
  def can_be_matrix?
    matrix = self.to_matrix
    return false if matrix == nil
    return true
  end
  
  def to_matrix
    return nil if not self[0].is_a?(Array)
    matrix = Matrix.new
    for i in 0...self.size
      return nil if self[0].size != self[i].size
      matrix.push(self[i])
    end
    return matrix
  end
end

class Matrix < Array
  def to_array
    array = Array.new
    for i in 0...self.size
      return nil if self[0].size != self[i].size
      array.push(self[i])
    end
    return array
  end
  
  def [](*args)
    if args.size == 1
      super
    else
      return self[args[0]][args[1]]
    end
  end
  
  def clone
    array = []
    for i in 0...self.size
      array.push([])
    end
    for i in 0...self.size
      for j in 0...self[i].size
        array[i].push([])
      end
    end
    result = array.to_matrix
    for i in 0...result.size
      for j in 0...result[i].size
        result[i][j] = self[i][j]
      end
    end
    return result
  end
  
  def nitems
    return self.size*self[0].size
  end
  
  def width
    return self[0].size
  end
  
  def height
    return self.size
  end
  
  def square?
    return width == height
  end
  
  def row(index)
    return self[index]
  end
  
  def column(index)
    result = []
    for i in 0...self.size
      result.push(self[i][index])
    end
    return result
  end
  
  def insert_row(index, array=row(index))
    return nil if not array.is_a?(Array)
    return nil if array.size != width
    self.insert(index, array)
    self.compact!
    return self
  end
  
  def insert_column(index, array=column(index))
    return nil if not array.is_a?(Array)
    return nil if array.size != height
    for i in 0...self.size
      self[i].insert(index, array[i])
      self[i].compact!
    end
    return self
  end
  
  def delete_row(array)
    return if not array.is_a?(Array)
    self.delete(array)
    return self
  end
  
  def delete_column(array)
    return if not array.is_a?(Array)
    for i in 0...self.size
      self[i].delete(index)
    end
    return self
  end
  
  def delete_row_at(index)
    self.delete_at(index)
    return self
  end
  
  def delete_column_at(index)
    for i in 0...self.size
      self[i].delete_at(index)
    end
    return self
  end
          
  def +(other)
    return false if not other.is_a?(Matrix)
    return false if self.size != other.size
    for i in 0...self.size
      return false if self[i].size != other[i].size
      for j in 0...self[i].size
        return false if not self[i][j].is_a?(Numeric)
        return false if not other[i][j].is_a?(Numeric)
      end
    end
    result = self.clone
    for i in 0...self.size
      for j in 0...self[i].size
        result[i][j] = self[i][j] + other[i][j]
      end
    end
    return result
  end
  
  def -(other)
    return false if not other.is_a?(Matrix)
    return false if self.size != other.size
    for i in 0...self.size
      return false if self[i].size != other[i].size
      for j in 0...self[i].size
        return false if not self[i][j].is_a?(Numeric)
        return false if not other[i][j].is_a?(Numeric)
      end
    end
    result = self.clone
    for i in 0...self.size
      for j in 0...self[i].size
        result[i][j] = self[i][j] - other[i][j]
      end
    end
    return result
  end
  
  def *(other)
    case other
    when Numeric
      result = self.clone
      for i in 0...self.size
        for j in 0...self[i].size
          result[i][j] = self[i][j] * other
        end
      end
    when Matrix
      return false if other.height != self.width
      res = []
      min = [other.width, self.height].min
      self.height.times{res.push([])}
      for i in 0...self.height
        min.times{res[i].push(0)}
      end
      result = res.to_matrix
      for i in 0...result.height
        for j in 0...result.width
          a = self.row(i)
          b = other.column(j)
          c = 0
          for k in 0...a.size
            c += a[k]*b[k]
          end
          result[i][j] = c
        end
      end
    end
    return result
  end
  
  def self.Make0(n)
    array = []
    n.times{array.push([])}
    for i in 0...n
      n.times{array[i].push(0)}
    end
    matrix = array.to_matrix
    return matrix
  end
  
  def self.Identity(n)
    matrix = self.Make0(n)
    for i in 0...n
      matrix[i][i] = 1
    end
    return matrix
  end
  
  def transpose
    array = []
    self.width.times{array.push([])}
    for i in 0...self.width
      self.height.times{array[i].push([])}
    end
    matrix = array.to_matrix
    for i in 0...self.width
      for j in 0...self.height
        matrix[i][j] = self[j][i]
      end
    end
    return matrix
  end
  
  def get_adjunt(row_index, column_index=0)
    matrix = self.clone
    matrix.delete_row_at(column_index)
    matrix.delete_column_at(row_index)
    return matrix
  end
  
  def determinant
    return self[0][0] if self.size == 1
    return false if not self.square?
    result = 0
    for i in 0...self.width
      adj = self.get_adjunt(i)
      if i%2==0
        result += (self.row(0)[i] * adj.determinant)
      else
        result += (self.row(0)[i] * adj.determinant) * (-1)
      end
    end
    return result
  end
  
  def matrix_adjunt
    return self[0][0] if self.size == 1
    return false if not self.square?
    result = self.clone
    for i in 0...self.width
      for j in 0...self.height
        adj = self.get_adjunt(i,j).determinant
        if (i+j)%2==0
          result[i][j] = adj * (-1)
        else
          result[i][j] = adj
        end
      end
    end
    return result
  end
  
  def inverse
    result = self.clone
    det = result.determinant
    return false if det == 0
    adj = result.matrix_adjunt * (-1)
    return adj * (1/det.to_f)
  end
end

Os pongo lo que añadí a las array normales

Array

can_be_matrix? - Comprueba si una array puede ser una matriz, para ello es necesario que sea una array de arrays y que cada una de sus arrays tenga el mismo tamaño.
to_matrix - Pasa la Array a Matrix, que es igual solo que con las funcionalidades extra. La matriz tendrá ésta estructura [[a,b],[c,d],[e,f]] por ejemplo. Ésto sería lo equivalente en código a esto:

Matrix < Array

to_array - Pasa la Matrix a Array de nuevo.
[a,b] - Devuelve el valor de posición a,b (fila y columna) de la matriz. Aún así es lo mismo poner array[0,1] que array[0][1]
nitems - Devuelve el número total de índices, fila x columna
width - Número de filas
height - Número de columnas
square? - Comprueba si es una matriz cuadrada (de 1x1, 2x2, 3x3...)
row(index) - Devuelve la fila [index] como una array
column(index) - Devuelve la columna [index] como una array
insert_row(index, array) - Inserta una fila [array] en la posición index.
insert_column(index, array) - Inserta una columna[array] en la posición index.
delete_row(array) - Borra las filas que sean iguales que array
delete_column(array) - Borra las columnas que sean iguales que array
delete_row_at(index) - Borra la fila de posición index
delete_column_at(index) - Borra la columna de posición index
+ - Suma matricial. También funciona +=
- - Resta matricial. También funciona -=
* - Producto matricial, con un número u otra matriz.
Matrix.Make0(n) - Crea una matriz de zeros, de tamaño n
Matrix.Identity(n) - Crea una matriz identidad, de tamaño n
transpose - Hace la matriz transpuesta
get_adjunt(row_index, column_index=0) - Devuelve el adjunto de la posición row_index, column_index de la matriz.
determinant - Calcula el determinante de la matriz.
matrix_adjunt - Crea la matriz de los adjuntos, substituyendo cada índice de la matriz por su adjunto.
inverse - Devuelve la inversa de la matriz.

Sé que el script no es perfecto, ya sabéis que hacer este tipo de códigos no es fácil, pero en fin hice lo que pude xD Cualquier mejora que se os ocurra podéis decirla o hacerla. El script es compatible con el último que puso Eron.


Última edición por Wecoc el Mar 6 Feb 2018 - 11:39, editado 1 vez
avatar
Wecoc
Administrador
Administrador



Créditos 12290

Gracias : 564

Volver arriba Ir abajo

Re: [RMXP/VX] [Herramienta de scripter] Array +

Mensaje por Wecoc el Vie 13 Sep 2013 - 23:25

Vengo a presentaros una nueva versión del script Matrix; la definitiva.

Permite crear matrices directamente usando Matrix antes de la array, por ejemplo:

Matrix[[1,2,3],[3,0,6],[1,4,3]]

Aún así el to_matrix de la array sigue funcionando igual. Además permite crear matrices según filas, columnas o su diagonal.

Matrix.rows [[1,2,3],[3,0,6],[1,4,3]]
Matrix.columns [[1,2,3],[3,0,6],[1,4,3]]
Matrix.diagonal(1, 2, 3, 4)


Esas son las actualizaciones más importantes.

Código:
class Array
  def can_be_matrix?
    matrix = self.to_matrix
    return false if matrix == nil
    return true
  end
 
 def to_matrix
    return nil if not self[0].is_a?(Array)
    matrix = Matrix.new
    for i in 0...self.size
      return nil if self[0].size != self[i].size
      matrix.push(self[i])
    end
    return matrix
  end
end

class Matrix < Array
  
  def Matrix.[](*args)
    return args.to_matrix
  end
  
  def Matrix.rows(array)
    return array.to_matrix
  end

  def Matrix.columns(array)
    return array.transpose.to_matrix
  end
  
  def Matrix.diagonal(*args)
    result = Matrix.Identity(args.size)
    for n in 0...args.size
      result[n][n] = args[n]
    end
    return result
  end
  
  def Matrix.Make0(n)
    array = []
    n.times{array.push([])}
    for i in 0...n
      n.times{array[i].push(0)}
    end
    matrix = array.to_matrix
    return matrix
  end
  
  def Matrix.Identity(n)
    return self.Scalar(n, 1)
  end
  
  def Matrix.Scalar(n, value)
    matrix = self.Make0(n)
    for i in 0...n
      matrix[i][i] = value
    end
    return matrix
  end
  
  def to_a
    array = Array.new
    for i in 0...self.size
      return nil if self[0].size != self[i].size
      array.push(self[i])
    end
    return array
  end
 
 def [](*args)
    if args.size == 1
      super
    else
      return self[args[0]][args[1]]
    end
  end
 
 def clone
    array = []
    for i in 0...self.size
      array.push([])
    end
    for i in 0...self.size
      for j in 0...self[i].size
        array[i].push([])
      end
    end
    result = array.to_matrix
    for i in 0...result.size
      for j in 0...result[i].size
        result[i][j] = self[i][j]
      end
    end
    return result
  end
 
 def nitems
    return self.size*self[0].size
  end
  
  def width
    return self[0].size
  end
  
  def height
    return self.size
  end
 
 unless $@
    alias row_size width
    alias column_size height
  end
  
  def square?
    return width == height
  end
  
  def row(index)
    return rows[index]
  end
  
  def column(index)
    return columns[index]
  end
  
 def rows(*args)
    array = self.to_a
    return args.size != 0 ? array.indexes(*args) : array
  end
  
  def columns(*args)
    array = self.to_a.transpose
    return args.size != 0 ? array.indexes(*args) : array
  end
  
  def diagonal
    array = []
    for i in 0...self.rows.size
      array << self[i][i]
    end
    return array
  end

  
  def insert_row(index, array=row(index))
    return nil if not array.is_a?(Array)
    return nil if array.size != width
    self.insert(index, array)
    self.compact!
    return self
  end
 
 def insert_column(index, array=column(index))
    return nil if not array.is_a?(Array)
    return nil if array.size != height
    for i in 0...self.size
      self[i].insert(index, array[i])
      self[i].compact!
    end
    return self
  end
 
 def delete_row(array)
    return if not array.is_a?(Array)
    self.delete(array)
    return self
  end
 
 def delete_column(array)
    return if not array.is_a?(Array)
    for i in 0...self.size
      self[i].delete(index)
    end
    return self
  end
 
 def delete_row_at(index)
    self.delete_at(index)
    return self
  end
 
 def delete_column_at(index)
    for i in 0...self.size
      self[i].delete_at(index)
    end
    return self
  end
  
  def +(other)
    return false if not other.is_a?(Matrix)
    return false if self.size != other.size
    for i in 0...self.size
      return false if self[i].size != other[i].size
      for j in 0...self[i].size
        return false if not self[i][j].is_a?(Numeric)
        return false if not other[i][j].is_a?(Numeric)
      end
    end
    result = self.clone
    for i in 0...self.size
      for j in 0...self[i].size
        result[i][j] = self[i][j] + other[i][j]
      end
    end
    return result
  end
 
 def -(other)
    return false if not other.is_a?(Matrix)
    return false if self.size != other.size
    for i in 0...self.size
      return false if self[i].size != other[i].size
      for j in 0...self[i].size
        return false if not self[i][j].is_a?(Numeric)
        return false if not other[i][j].is_a?(Numeric)
      end
    end
    result = self.clone
    for i in 0...self.size
      for j in 0...self[i].size
        result[i][j] = self[i][j] - other[i][j]
      end
    end
    return result
  end
 
 def *(other)
    case other
    when Numeric
      result = self.clone
      for i in 0...self.size
        for j in 0...self[i].size
          result[i][j] = self[i][j] * other
        end
      end
    when Matrix
      return false if other.height != self.width
      res = []
      min = [other.width, self.height].min
      self.height.times{res.push([])}
      for i in 0...self.height
        min.times{res[i].push(0)}
      end
      result = res.to_matrix
      for i in 0...result.height
        for j in 0...result.width
          a = self.row(i)
          b = other.column(j)
          c = 0
          for k in 0...a.size
            c += a[k]*b[k]
          end
          result[i][j] = c
        end
      end
    end
    return result
  end
  
  def transpose
    super
  end
 
 def get_adjunt(row_index, column_index=0)
    matrix = self.clone
    matrix.delete_row_at(column_index)
    matrix.delete_column_at(row_index)
    return matrix
  end
 
 def determinant
    return self[0][0] if self.size == 1
    return false if not self.square?
    result = 0
    for i in 0...self.width
      adj = self.get_adjunt(i)
      if i%2==0
        result += (self.row(0)[i] * adj.determinant)
      else
        result += (self.row(0)[i] * adj.determinant) * (-1)
      end
    end
    return result
  end
 
 def matrix_adjunt
    return self[0][0] if self.size == 1
    return false if not self.square?
    result = self.clone
    for i in 0...self.width
      for j in 0...self.height
        adj = self.get_adjunt(i,j).determinant
        if (i+j)%2==0
          result[i][j] = adj * (-1)
        else
          result[i][j] = adj
        end
      end
    end
    return result
  end
 
 def inverse
    result = self.clone
    det = result.determinant
    return false if det == 0
    adj = result.matrix_adjunt * (-1)
    return adj * (1/det.to_f)
  end
  
  def collect
    rows = self.rows.collect{|row| row.collect{|e| yield e}}
    return rows.to_matrix
  end
  alias map collect unless $@
  
  def rank
    if self.columns.size > self.rows.size
      a = transpose.to_a
      a_column_size = self.rows.size
      a_row_size = self.columns.size
    else
      a = to_a
      a_column_size = self.columns.size
      a_row_size = self.rows.size
    end
    rank = 0
    k = 0
    begin
      if (akk = a[k][k]) == 0
        i = k
        exists = true
        begin
          if (i += 1) > a_column_size - 1
            exists = false
              break
            end
        end while a[i][k] == 0
        if exists
          a[i], a[k] = a[k], a[i]
          akk = a[k][k]
        else
          i = k
          exists = true
          begin
            if (i += 1) > a_row_size - 1
              exists = false
              break
            end
          end while a[k][i] == 0
          if exists
            k.upto(a_column_size - 1) do
              |j|
              a[j][k], a[j][i] = a[j][i], a[j][k]
            end
            akk = a[k][k]
          else
            next
          end
        end
      end
      (k + 1).upto(a_row_size - 1) do
        |i|
        q = a[i][k] / akk
        (k + 1).upto(a_column_size - 1) do
          |j|
          a[i][j] -= a[k][j] * q
        end
      end
      rank += 1
    end while (k += 1) <= a_column_size - 1
    return rank
  end
  
  def regular?
    square? and rank == columns.size
  end
  
  def singular?
    !regular?
  end
  
  def trace
    n = 0
    for i in 0...self.diagonal.size
      n += self.diagonal[i]
    end
    return n
  end
  
  def minor(*param)
    case param.size
    when 2 # col_range, row_range
      from_row = param[0].first
      size_row = param[0].end - from_row
      size_row += 1 unless param[0].exclude_end?
      from_col = param[1].first
      size_col = param[1].end - from_col
      size_col += 1 unless param[1].exclude_end?
    when 4 # start_row, nrows, start_col, ncols
      from_row = param[0]
      size_row = param[1]
      from_col = param[2]
      size_col = param[3]
    end
    r = self.rows[from_row, size_row].collect{
      |row|
      row[from_col, size_col]
    }
    Matrix.rows(r)
  end
end
Aquí una lista de sus funciones actuales:

to_a - Pasa la Matrix a Array.
[a,b] - Devuelve el valor de posición a,b (fila y columna) de la matriz. Aún así es lo mismo poner array[0,1] que array[0][1]
nitems - Devuelve el número total de índices, fila x columna
width - Número de filas (también se puede usar row_size)
height - Número de columnas (también se puede usar column_size)
square? - Comprueba si es una matriz cuadrada (de 1x1, 2x2, 3x3...)
row(index) - Devuelve la fila [index] como una array
column(index) - Devuelve la columna [index] como una array
rows(*indexes) - Idéntico a row pero con más de un índice a la vez.
columns(*indexes) - Idéntico a column pero con más de un índice a la vez.
diagonal - Devuelve la diagonal de la matriz.
insert_row(index, array) - Inserta una fila [array] en la posición index.
insert_column(index, array) - Inserta una columna[array] en la posición index.
delete_row(array) - Borra las filas que sean iguales que array
delete_column(array) - Borra las columnas que sean iguales que array
delete_row_at(index) - Borra la fila de posición index
delete_column_at(index) - Borra la columna de posición index
+ - Suma matricial. También funciona +=
- - Resta matricial. También funciona -=
* - Producto matricial, con un número u otra matriz.
Matrix.Make0(n) - Crea una matriz de zeros, de tamaño n
Matrix.Identity(n) - Crea una matriz identidad, de tamaño n
Matrix.Scalar(n, value) - Crea una escalar (es como la identidad pero en vez de con 1, con value) de tamaño n.
transpose - Hace la matriz transpuesta
get_adjunt(row_index, column_index=0) - Devuelve el adjunto de la posición row_index, column_index de la matriz.
determinant - Calcula el determinante de la matriz.
matrix_adjunt - Crea la matriz de los adjuntos, substituyendo cada índice de la matriz por su adjunto.
inverse - Devuelve la inversa de la matriz.
collect - A cada índice le aplica un cambio (como el collect de array pero especializado para matrices)
map - Idéntico a collect.
rank - Devuelve el rango de la matriz.
regular? - Mira si la matriz es regular, es decir si es cuadrada y su rango equivale al número de filas (o columnas)
singular? - Mira si la matriz es singular, es decir que no es regular.
trace - Calcula la suma de los valores de la diagonal.
minor(range_row, range_col) - Devuelve la menor de la matriz que queda dentro del rango establecido.
minor(start_row, nrows, start_col, ncols) - Devuelve la menor de la matriz que queda dentro del rango establecido.

El script sigue siendo compatible con el de Eron, y en principio vale para cualquier RPG maker.
avatar
Wecoc
Administrador
Administrador



Créditos 12290

Gracias : 564

Volver arriba Ir abajo

Re: [RMXP/VX] [Herramienta de scripter] Array +

Mensaje por Wecoc el Vie 14 Mar 2014 - 0:50

Vengo a necrotriplepostear porque he hecho una adaptación al RPG maker de un fragmento de un script para Ruby llamado "Hash Utils" y que tiene funciones extras para Hash y Array de un estilo similar a las ya puestas. Es compatible con todo lo puesto hasta el momento en éste extraño topic. No conozco el funcionamiento de todos métodos pero parece que funcionan. Os pongo unos ejemplos aquí en azul.

p ["A", "B"].complete_to(4, "C") # => ["A", "B", "C", "C"]
p ["A", "B"].complete_to(1, "C") # => ["A"]
p ["A", "B", "C"].cut(1) # => ["A", "B"]
p ["A", "B", "C"].drop(1) # => ["B", "C"]
p ["A", "B", "C"].shrink_to(1) # => ["A"]
p ["A", "D"].expand_by("C") # => ["A", "C", "D", "C"]
p ["L", "D"].interlace("S") # => ["L", "S", "D"]
p [0, 1, 2, 3].to_hash # => { 0=>1, 2=>3 }
p ["A", "B"].merge!( ["a", "b"] ) # => ["A", "B", "a", "b"]

p Hash.combine(["A", "B"], ["a", "b"] ) # => { "A"=>"a", "B"=>"b" }

hash = {"A"=>0, "B"=>1 }
p hash .get_items("A") # => {"A"=>0} # Parece ser lo mismo que take_items
p hash .get_values("A") # => [0] # Parece ser lo mismo que take_values


Aquí el script, y si no comentáis nada no os sorprenda que haga un 4o post xD

Código:
#==============================================================================
# ** Hash Utils
# Adaptación a RPG maker (XP, VX y Ace)
#==============================================================================

class Array
  def complete_to(length, member = nil)
    self.dup.complete_to!(length, member)
  end
 
  def complete_to!(length, member = nil)
    delta = length - self.length
    if delta > 0
      fill = [member] * delta
    self.push(*fill)
  elsif delta == 0
      self
    else
      self.shrink_to!(length)
    end
  end
 
  def cut(length)
    self.dup.cut!(length)
  end
 
  def cut!(length)
    delta = self.length - length
    if delta >= 0
      self.slice! delta..(self.length)
      self
    else
      self.clear
    end
  end
 
  def shrink_to(length)
    self.dup.shrink_to! length
  end
 
  def shrink_to!(length)
    delta = self.length - length
    if delta > 0
      self.cut! self.length - length
    else
      self
    end
  end
 
  def drop(length)
    self.dup.drop!(length)
  end
 
  def drop!(length)
    if length > 0
      self.slice! 0..(length - 1)
      self
    else
      self
    end
  end
 
  def expand_by(*objects)
    self.dup.expand_by!(*objects)
  end
 
  def expand_by!(*objects)
    if self.empty?
      self
    else
      self.map! { |i| i = [i]; i += objects }.flatten!
    end
  end
 
  def interlace(*objects)
    self.dup.interlace!(*objects)
  end
 
  def interlace!(*objects)
    self.expand_by!(*objects).cut! objects.length
  end
 
  def merge!(*arrays)
    arrays.flatten!
    self.push(*arrays)
    self
  end
 
  def remove!(&block)
    result = [ ]
    self.reject! do |v|
      if block.call(v)
        result << v
        true
      else
        false
      end
    end
    return result
  end
     
  def to_hash
    Hash[*self]
  end
end

class Hash
  def self.combine(keys, values)
    result = { }
    keys.each_index do |i|
      result[keys[i]] = values[i]
    end
    return result
  end
 
  def self.create(default = nil, hash = nil, &block)
    if not hash.nil?
      hash = hash.dup
    else
      hash = { }
    end
    hash.default = default
    hash.default_proc = block if not block.nil?
    return hash       
  end
 
  def self.define(values = {}, default = nil, &block)
  hash = self[values]
    self::create(default, hash, &block)
  end
 
  def all_pairs?(&block)
    return true if self.empty?
    self.each_pair do |k, v|
      if block.call(k, v) == false
        return false
      end
    end
    return true
  end
 
  def get_items(*args)
    result = { }
    self.get_pairs(*args) do |key, value|
      result[key] = value
    end
    return result
  end
 
  def get_pairs(*args) # No sé como funciona
    self.take_pairs(*args) do |i|
      yield i if not i[1].nil?
    end
  end
 
  def get_values(*args)
    result = [ ]
    self.get_pairs(*args) do |key, value|
      result << value
    end
    return result
  end
 
  def has_all?(keys)
    keys.each do |key|
      if not self.has_key? key
        return false
      end
    end
    return true
  end
 
  def has_some?(keys)
    keys.each do |key|
      if self.has_key? key
        return true
      end
    end
    return false
  end
 
  def keys_to_sym
    self.map_keys do |k|
    if k.kind_of?(String)
        k.to_sym
    else
        k
      end
    end
  end
 
  def keys_to_sym!
    self.replace(self.keys_to_sym)
  end
   
  def map_keys(&block)
    self.map_pairs do |k, v|
      [block.call(k), v]
    end
  end
 
  def map_keys!(&block)
    self.replace(self.map_keys(&block))
  end
 
  def map_pairs(&block)
    _new = self.recreate
    self.each_pair do |k, v|
      new_k, new_v = block.call(k, v)
      _new[new_k] = new_v
    end
    return _new
  end
 
  def map_pairs!(&block)
    self.replace(self.map_pairs(&block))
  end
 
  def map_values(&block)
    self.map_pairs do |k, v|
      [k, block.call(v)]
    end
  end
 
  def map_values!(&block)
    self.replace(self.map_values(&block))
  end
     
  def some?(&block)
    self.each_value do |v|
      return true if block.call(v)
    end
    return false
  end
 
  def some_pairs?(&block)
    self.each_pair do |pair|
      return true if block.call(pair)
    end
    return false
  end
     
  def take_items(*args)
    result = { }
    self.take_pairs(*args) do |key, value|
      result[key] = value
    end
    return result
  end
 
  def take_pairs(*args)
    args.each do |i|
      yield [i, self[i]]
    end
  end
 
  def take_values(*args)
    result = [ ]
    self.take_pairs(*args) do |key, value|
      result << value
    end
    return result
  end
end

Array

complete_to | complete_to!
cut | cut!
shrink_to | shrink_to!
drop | drop!
expand_by | expand_by!
interlace | interlace!
merge!
remove!
to_hash


Hash

Hash.combine
Hash.create
Hash.define
all_pairs?
get_items
get_pairs
get_values
has_all?
has_some?
keys_to_sym | keys_to_sym!
map_keys | map_keys!
map_pairs | map_pairs!
map_values | map_values!
some?
some_pairs?
take_items
take_pairs
take_values


Y 5 cosas para complementar:
Os pongo 5 cosas extras que pueden interesaros sobre el uso de las Array y Hash (aunque algunas son aplicables a todo xD), y que en general tienen que ver con los scripts aportados en éste topic hasta el momento.

1 - Se puede acceder a las cosas de la clase desde fuera de ella con instance_eval y instance_exec

Código:
class KlassWithSecret
  def initialize
    @secret = 99
  end
end
k = KlassWithSecret.new
k.instance_eval { @secret }  #=> 99

class KlassWithSecret
  def initialize
    @secret = 99
  end
end
k = KlassWithSecret.new
k.instance_exec(1) {|x| @secret + x }  #=> 100 ## (99 + 1)

2 - En general los métodos que tienen self.nombre se llaman desde el nombre de la clase en genenral y no desde un ejemplo de ésta en concreto, por ejemplo el Hash.create de antes (eso es básico).
Pero los demás también se pueden llamar así usando allocate, si el método funciona con return o similar (la mayoría) y no depende estrictamente de self

Código:
class Array
  def hola
    return "Hola"
  end
end
p [0,1].hola #=> "Hola"
p Array.allocate.hola #=> "Hola"

3 - Es importante tener en cuenta que el uso de los block puede ser vital para el funcionamiento de algunos métodos pero también para lograr alternativas de otros que en realidad no lo requieren.

Código:
h1 = { "a" => 100, "b" => 200 }
h2 = { "b" => 254, "c" => 300 }
p h1.merge(h2)
# { "a" => 100, "b" => 254, "c" => 300 }
p h1.merge(h2){|key, oldval, newval| newval - oldval}
# { "a" => 100, "b" => 54, "c" => 300 }

Código:
p Array.new(3, rand(100)) # => [28,28,28]
p Array.new(3) { rand(100) } # => [10,53,27]

4 - El uso de * delante de la array tiene muchas utilidades a parte del típico *args. Lo que hace * es considerar cada elemento de la array ordenadamente e individualmente y no como un conjunto. Con Hash hace lo mismo paro pasando cada par a array.

Código:
a = { :name => "Fred", :age => 93 }
p [a]  # => [{:name => "Fred", :age =>93}]
p [*a] # => [[:name, "Fred"], [:age, 93]]

Código:
a = ["a", "b"]
b = ["c", "d"]
p a + b  # => ["a", "b", "c", "d"]
p [a + b]  # => [["a", "b", "c", "d"]]
p [*a + b] # => ["a", "b", "c", "d"]

Código:
a = ["a", "b", "c", "d", "e", "f", "g", "h"]
b = [0, 5, 6]
p a.values_at(*b) # => ["a", "f", "g"]

Código:
fruit = ["apple","red","banana","yellow"]
p Hash[*fruit] # => {"apple"=>"red", "banana"=>"yellow"}

5 - Un Hash se puede usar para definir un nuevo "método" interno de lectura booleana entre otras cosas raras.

Código:
does = { true => 'Yes', false => 'No' }
p does[10 == 50] # => "No"
p does[10 > 5]  # => "Yes"
avatar
Wecoc
Administrador
Administrador



Créditos 12290

Gracias : 564

Volver arriba Ir abajo

Re: [RMXP/VX] [Herramienta de scripter] Array +

Mensaje por orochii el Vie 14 Mar 2014 - 5:41

p ["A", "D"].expand_by("C") # => ["A", "C", "D", "C"]
p ["L", "D"].interlace("S") # => ["L", "S", "D"]
x'DDDDD... It's magic!

Cut y drop son como un multi-pop y multi-shift, interesante. Y los que rellenan tan guays, aunque dependen mucho de lo que quieras hacer. Sería tenerlos en cuenta xD.

Tan guays los métodos al final, toous.
avatar
orochii
Reportero

0/3

Créditos 7595

Gracias : 403

Volver arriba Ir abajo

Re: [RMXP/VX] [Herramienta de scripter] Array +

Mensaje por Wecoc el Jue 25 Ene 2018 - 0:04

Nueva versión 1.2 de Array+ ya disponible

Los métodos han sido optimizados, y se han quitado algunos que resultaron ser innecesarios puesto que pueden recrearse fácilmente con métodos por defecto de RGSS. Además se han añadido algunos métodos de combinatoria y permutación propios del Ruby 2.5.0 y se han ampliado los ejemplos.

Ojalá os sirva. Recordad que no tiene por qué usarse entera, pueden usarse solo los métodos sueltos que se requiera, pero vigilad que no estén usado otros métodos de Array+ de modo interno.

Código:
#==============================================================================
# ** [Herramienta de scripter] Array +
#------------------------------------------------------------------------------
#  Nuevas funciones para la class Array
#  Versión: 1.2
#  by: Wecoc, Newold & Eron (no hace falta dar créditos)
#------------------------------------------------------------------------------
# Array.normalize_size(a, b)
# Array.suma(ary1, ary2 ...)
# Array.resta(ary1, ary2 ...)
# sort_by(:sym)
# max_by(:sym)
# min_by(:sym)
# subset?(other)
# superset?(other)
# powerset
# combination_set
# combination(n)
# permutation_set
# permutation(n)
# product(ary)
# product(ary1, ary2)
# repeated_combination(n)
# repeated_permutation(n)
# sample
# count
# after
# rotate([n])
# strip_values_at!(ix1, ix2 ...)
# extract! { block }
# to_hash
# into_hash(hash)
# uniq_count
# average
# geo_average
# har_average
# variance
# stand_dev
# median
# Array.covariance(ary1, ary2)
#==============================================================================

class Array
  
  #**************************************************************************
  #   Aritmética (Wecoc)
  #**************************************************************************
  
  #--------------------------------------------------------------------------
  # * normalize_size
  #--------------------------------------------------------------------------
  # Iguala el tamaño de dos arrays al máximo entre ambas.
  # Array.normalize_size([2,4],[1]) #=> [2,4], [1,0]
  #--------------------------------------------------------------------------
  def Array.normalize_size(a, b, val=0)
    loop do
      break if a.size == b.size
      if a.size < b.size
        a.push(val)
      else
        b.push(val)
      end
    end
    return a, b
  end
  #--------------------------------------------------------------------------
  # * suma (nueva)
  #--------------------------------------------------------------------------
  # Con la suma normal: [2,4]+[1,2] #=> [2,4,1,2]
  # Array.suma([2,4],[1,2]) #=> [3,6]
  # Nota: Se pueden sumar muchas array a la vez.
  #--------------------------------------------------------------------------
  def Array.suma_2(a, b)
    Array.normalize_size(a, b)
    c = []
    for i in 0...a.size
      c[i] = a[i] + b[i]
    end
    return c
  end
  def Array.suma(*args)
    return nil if args.size == 0
    return args[0] if args.size == 1
    cloned_args = args.clone
    loop do
      result = Array.suma_2(cloned_args[0], cloned_args[1])
      cloned_args.shift ; cloned_args.shift
      cloned_args.insert(0, result)
      return result if cloned_args.size == 1
    end
  end
  #--------------------------------------------------------------------------
  # resta (nueva)
  #--------------------------------------------------------------------------
  # Con la resta normal: [2,4]-[1,2] #=> [4]
  # Array.resta([2,4],[1,2]) #=> [1,2]
  # Nota: Se pueden restas muchas array a la vez.
  #--------------------------------------------------------------------------
  def self.resta_2(a,b)
    Array.normalize_size(a, b)
    c = []
    for i in 0...a.size
      c[i] = a[i] - b[i]
    end
    return c
  end
  def self.resta(*args)
    return nil if args.size == 0
    return args[0] if args.size == 1
    cloned_args = args.clone
    loop do
      result = Array.resta_2(cloned_args[0], cloned_args[1])
      cloned_args.shift ; cloned_args.shift
      cloned_args.insert(0, result)
      return result if cloned_args.size == 1
    end
  end
  
  #**************************************************************************
  #   Comparadores (Wecoc)
  #**************************************************************************
  
  include Comparable
  
  #**************************************************************************
  #   Enumeradores (Wecoc)
  #**************************************************************************

  #--------------------------------------------------------------------------
  # * sort_by
  #--------------------------------------------------------------------------
  # Sirve para poder ordenar cualquier data según un parámetro concreto
  # Ejemplo: En Window_Item para poder ordenar los objetos por:
  # # id --> @data.sort_by(:id)
  # # nombre --> @data.sort_by(:name)
  # # precio --> @data.sort_by(:price)
  #--------------------------------------------------------------------------
  def sort_by(sym)  self.sort {|x,y| x.send(sym) <=> y.send(sym) }  end
  def sort_by!(sym) self.sort!{|x,y| x.send(sym) <=> y.send(sym) }  end
  #--------------------------------------------------------------------------
  # * max_by / min_by
  #--------------------------------------------------------------------------
  # Sirven para poder obtener el mayor o menor valor de la array según un
  # parámetro concreto, su funcionamiento es igual que el sort_by
  #--------------------------------------------------------------------------
  def max_by(sym)   self.max {|x,y| x.send(sym) <=> y.send(sym) }   end
  def min_by(sym)   self.min {|x,y| x.send(sym) <=> y.send(sym) }   end

  #**************************************************************************
  #   Combinatoria (Wecoc)
  #**************************************************************************

  #--------------------------------------------------------------------------
  # * subset?(other) / superset?(other)
  #--------------------------------------------------------------------------
  # Comprueba si uno incluye al otro de forma similar al include
  # a = [1, 2, 3, 4]
  # b = [2, 3]
  # c = [2, 3, 4, 5]
  # flag1 = c.subset? a    # false
  # flag2 = b.subset? a    # true
  # flag3 = c.superset? b  # true
  #--------------------------------------------------------------------------
  def subset?(other)
    self.each do |x|
      return false if !(other.include? x)
    end
    return true
  end
  def superset?(other)
    other.subset?(self)
  end
  #--------------------------------------------------------------------------
  # * combination_set
  # * powerset
  #--------------------------------------------------------------------------
  # Busca todas las combinaciones posibles entre los elementos de una array.
  # Nota: no confundir combinación con permutación
  # x = [1, 2, 3]
  # y = x.powerset #=> [[], [1], [2], [1,2], [3], [1,3], [2,3], [1,2,3]]
  #--------------------------------------------------------------------------
  def combination_set
    num = 2 ** size
    result = Array.new(num, [])
    self.each_index do |i|
      a = 2 ** i
      b = 2 ** (i+1) - 1
      j = 0
      while j < num-1
        for j in (j+a)..(j+b)
          result[j] += [self[i]]
        end
        j += 1
      end
    end
    return result
  end
  alias_method(:powerset, :combination_set)
  #--------------------------------------------------------------------------
  # * combination
  #--------------------------------------------------------------------------
  # Hace un powerset pero con solo los resultados de tamaño n.
  # En otras palabras, hace la combinación entre los argumentos de la array.
  # x = [1, 2, 3]
  # y = x.combination(1) #=> [[1], [2], [3]]
  # y = x.combination(2) #=> [[1,2], [1,3], [2,3]]
  # y = x.combination(3) #=> [[1,2,3]]
  #--------------------------------------------------------------------------
  def combination(n=self.size)
    return [] if n > self.size
    return [[]] if n == 0
    return self.combination_set.select {|x| x.size == n}
  end
  #--------------------------------------------------------------------------
  # * permutation_set
  #--------------------------------------------------------------------------
  # Busca todas las permutaciones posibles entre los elementos de una array.
  # x = [1, 2, 3]
  # y = x.permutation_set #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
  #--------------------------------------------------------------------------
  def permutation_set
    result = []
    array = ("a".."z").to_a
    array.delete("i")
    array.delete("j")
    code = ""
    for i in 0...self.size
      code.concat("for #{array[i]} in 0...self.size;")
    end
    for i in 0...self.size
      for j in 0...self.size
        next if i == j
        code.concat("next if #{array[i]} == #{array[j]};")
      end
    end
    code.concat("result.push [")
    if self.size > 1
      for i in 0...(self.size - 1)
        code.concat("self[#{array[i]}], ")
      end
    end
    code.concat("self[#{array[self.size - 1]}]];")
    for i in 0...self.size
      code.concat("end;")
    end
    eval(code)
    return result.uniq
  end
  #--------------------------------------------------------------------------
  # * permutation
  #--------------------------------------------------------------------------
  # Obtiene todas las permutaciones de un tamaño determinado
  # [1, 2, 3].permutation(2) #=> [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]]
  #--------------------------------------------------------------------------
  def permutation(n=self.size)
    return [] if n > self.size
    return [[]] if n == 0
    set = self.permutation_set
    return set if n == self.size
    result = []
    for i in 0...set.size
      result[i] = set[i][0...n]
    end
    return result.uniq
  end
  #--------------------------------------------------------------------------
  # * product
  #--------------------------------------------------------------------------
  # Crea una array con las combinaciones entre sus números como si multiplicara
  # [1,2,3].product_2([4,5]) #=> [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]
  #
  # [1,2].product([3,4],[5,6]) #=>[[1,3,5],[1,3,6],[1,4,5],[1,4,6],
  #                            #  [2,3,5],[2,3,6],[2,4,5],[2,4,6]]
  # No funciona con más de 2 argumentos
  #--------------------------------------------------------------------------
  def product_2(array)
    a = result = []
    if array.is_a?(Numeric)
      for i in 0...self.size
        result[i] = self[i] * array
      end
      return result
    end
    return nil if array.size == 0
    if array.size == 1
      for i in 0...self.size
        result[i] = self[i] * array[0]
      end
      return result
    end
    for i in 0...self.size
      a = [self[i], array].flatten
      result += a.combination(array.size)
      result.pop
    end
    return result
  end
  def product(*args)
    result = []
    return nil if args.size == 0
    return self.product_2(*args) if args.size == 1
    if args.size == 2
      resprev = self.product_2(args[0])
      for i in 0...resprev.size
        for j in 0...args[1].size
          result.push(resprev[i] + args[1][j].to_a)
        end
      end
      return result
    end
  end
  #--------------------------------------------------------------------------
  # * repeated_combination
  #--------------------------------------------------------------------------
  # Crea una array con la combinación entre todos sus elementos, con repetición
  # a = [1, 2, 3]
  # a.repeated_combination(3) #=> [[1,1,1],[1,1,2],[1,1,3],[1,2,2],[1,2,3],
  # [1,3,3],[2,2,2],[2,2,3],[2,3,3],[3,3,3]]
  #--------------------------------------------------------------------------
  def repeated_combination(n)
    array = []
    for i in 0...self.size
      n.times { array.push(i) }
    end
    r = array.combination(n).uniq
    result = []
    for i in r
      result.push(self.values_at(*i))
    end
    return result
  end
  #--------------------------------------------------------------------------
  # * repeated_permutation
  #--------------------------------------------------------------------------
  # Crea una array con la permutación entre todos sus elementos, con repetición
  # a = [1, 2]
  # a.combination(2)           #=> [[1,2]]
  # a.permutation(2)           #=> [[1,2],[2,1]]
  # a.repeated_combination(2)  #=> [[1,1],[1,2],[2,2]]
  # a.repeated_permutation(2)  #=> [[1,1],[1,2],[2,1],[2,2]]
  #--------------------------------------------------------------------------
  def repeated_permutation(n)
    array = []
    for i in 0...self.size
      n.times { array.push(i) }
    end
    r = array.permutation(n).uniq
    result = []
    for i in r
      result.push(self.values_at(*i))
    end
    return result
  end
  
  #**************************************************************************
  #   Otros (Wecoc)
  #**************************************************************************
  
  #--------------------------------------------------------------------------
  # * sample
  #--------------------------------------------------------------------------
  # Obtiene valores al azar de dentro la Array, y los borra de la misma
  #--------------------------------------------------------------------------
  def sample(n=1)
    array = self.compact
    result = []
    for i in 0...n
      random = rand(array.size)
      result.push(array[random])
      array.delete_at(random)
    end
    return result
  end
  #--------------------------------------------------------------------------
  # * count
  #--------------------------------------------------------------------------
  # Cuenta cuantas veces sale cada valor
  #--------------------------------------------------------------------------
  def count
    result = Hash.new(0)
    self.each {|x| result[x] += 1 }
    return result
  end
  #--------------------------------------------------------------------------
  # * after
  #--------------------------------------------------------------------------
  # array = ["Hola", "Eron", "Mundo", "Wecoc", "Newold"]
  # array.after("Hola") #=> "Eron"
  # array.after("Hola",3) #=> "Wecoc"
  # array.after("Wecoc",-1) #=> "Mundo"
  #--------------------------------------------------------------------------
  def after(val,num=1)
    if self.include?(val)
      a = self.index(val)
      return self[a + num]
    else
      return nil
    end
  end
  #--------------------------------------------------------------------------
  # * rotate
  #--------------------------------------------------------------------------
  # Rota los valores de las arrays.
  # Esta clase forma parte de Ruby pero no de RGSS por eso la reescribí :3
  # ["a","b","c","d"].rotate #=> ["b","c","d","a"]
  # ["a","b","c","d"].rotate(-2) #=> ["c","d","a","b"]
  #--------------------------------------------------------------------------
  def rotate(n=1)
    return self if n == 0
    return self.reverse.rotate.reverse if n == -1
    if n == 1
      result = []
      for i in 0...self.size
        result[i] = self[0]
        result[i-1] = self[i]
      end
      return result
    end
    if n > 1
      a = self.rotate
      n.times { a = a.rotate }
      return a
    end
    if n < -1
      a = self.reverse
      n.abs.times { a = a.rotate }
      a = a.reverse
      return a
    end
  end
  #--------------------------------------------------------------------------
  # * strip_values_at!
  #--------------------------------------------------------------------------
  # Devuelve los valores de las posiciones que digas de la array.
  # a = [0, "a", 4, 3]
  # p a.strip_values_at!(1, 2) # => ["a", 4]
  # p a # => [0, 3]
  #--------------------------------------------------------------------------
  def strip_values_at!(*args)
    args.sort!{|b,a| a - b}
    result = []
    for i in args
      result.push(self[i])
      self.delete_at(i)
    end
    return result.reverse
  end
  #--------------------------------------------------------------------------
  # * extract!
  #--------------------------------------------------------------------------
  # Quita los valores que le digas de la array.
  # a = ("a".."h").to_a # => ["a", "b", "c", "d", "e", "f", "g", "h"]
  # p a.extract! { |x| x < "e" && x != "b" }     # => ["a", "c", "d"]
  # p a # => ["b", "e", "f", "g", "h"]
  #--------------------------------------------------------------------------
  def extract!(&block)
    ary = self.dup
    self.reject! { |x| yield x }
    ary - self
  end
  
  #**************************************************************************
  #   Array to Hash (NEWOLD)
  #**************************************************************************
  
  #--------------------------------------------------------------------------
  # * to_hash
  #--------------------------------------------------------------------------
  def to_hash
    hash = {}
    for i in 0...self.size
      hash[i] = self[i]
    end
    return hash
  end
  #--------------------------------------------------------------------------
  # * into_hash
  #--------------------------------------------------------------------------
  def into_hash(h)
    unless size % 2 == 0
      raise StandardError, "Expected array with even number of elements"
    end
    0.step(size-1, 2) { |x| h[self[x]] = self[x+1] }
    return h
  end
  #--------------------------------------------------------------------------
  # * uniq_count
  #--------------------------------------------------------------------------
  def uniq_count
    hash = {}
    each do |e|
      hash[e] ||= 0
      hash[e] += 1
    end
    return hash
  end
 
  #**************************************************************************
  #   Estadística (Eron)
  #**************************************************************************
  
  #--------------------------------------------------------------------------
  # * average
  #--------------------------------------------------------------------------
  # Calcula la media aritmética de los valores de la array.
  # Corresponde a la suma de los valores dividida por el número de valores.
  # Puede aplicarse a toda la array o a solo un rango.
  #--------------------------------------------------------------------------
  def average(s=0, e=self.size - 1)
    return 0 if self.size == 0
    return self[0] if self.size == 1
    real_s = [[s, 0].max, self.size - 1].min
    real_e = [[e, 0].max, self.size - 1].min
    s = [real_s, real_e].min
    e = [real_s, real_e].max
    return self[s] if s == e
    a = 0.0
    for i in s..e
      a += self[i]
    end
    n = (e - s) + 1.0
    return (a / n)
  end
  #--------------------------------------------------------------------------
  # * geo_average
  #--------------------------------------------------------------------------
  # Calcula la media geométrica de los valores de la array.
  # Multiplicación de los valores elevada a (1 / nº de valores).
  # Puede aplicarse a toda la array o a solo un rango.
  #--------------------------------------------------------------------------
  def geo_average(s=0, e=self.size - 1)
    return 0 if self.size == 0
    return self[0] if self.size == 1
    real_s = [[s, 0].max, self.size - 1].min
    real_e = [[e, 0].max, self.size - 1].min
    s = [real_s, real_e].min
    e = [real_s, real_e].max
    return self[s] if s == e
    a = 1.0
    for i in s..e
      a *= self[i]
    end
    n = (e - s) + 1.0
    return a ** (1 / n)
  end
  #--------------------------------------------------------------------------
  # * har_average
  #--------------------------------------------------------------------------
  # Calcula la media armónica de los valores de la array.
  # Inversa de la media aritmética de los inversos de los valores.
  # Puede aplicarse a toda la array o a solo un rango.
  #--------------------------------------------------------------------------
  def har_average(s=0, e=self.size - 1)
    return 0 if self.size == 0
    return self[0] if self.size == 1
    real_s = [[s, 0].max, self.size - 1].min
    real_e = [[e, 0].max, self.size - 1].min
    s = [real_s, real_e].min
    e = [real_s, real_e].max
    return self[s] if s == e
    a = 0.0
    for i in s..e
      return 0 if self[i] == 0
      a += (1 / self[i].to_f)
    end
    n = (e - s) + 1.0
    return (n / a)
  end
  #--------------------------------------------------------------------------
  # * variance
  #--------------------------------------------------------------------------
  # Calcula la variancia según la definición inferencial.
  # Puede aplicarse a toda la array o a solo un rango.
  #--------------------------------------------------------------------------
  def variance(s=0, e=self.size - 1)
    return 0 if self.size == 0
    return self[0] if self.size == 1
    real_s = [[s, 0].max, self.size - 1].min
    real_e = [[e, 0].max, self.size - 1].min
    s = [real_s, real_e].min
    e = [real_s, real_e].max
    return 0 if s == e
    aver = self.average(s, e)
    a = 0.0
    n = (e - s) + 1.0
    for i in s..e
      a += ((self[i] - aver) ** 2) / (n - 1.0)
    end
    return a
  end
  #--------------------------------------------------------------------------
  # * stand_dev
  #--------------------------------------------------------------------------
  # Calcula la desviación estándar según la definición inferencial.
  # Eso equivale a la raíz de la variancia.
  #--------------------------------------------------------------------------
  def stand_dev(s=0, e=self.size - 1)
    return Math.sqrt(self.variance(s, e))
  end
  #--------------------------------------------------------------------------
  # * median
  #--------------------------------------------------------------------------
  # Devuelve la mediana de la array ordenada.
  # Puede aplicarse a toda la array o a solo un rango.
  #--------------------------------------------------------------------------
  def median(s=0, e=self.size - 1, rounded=true)
    return 0 if self.size == 0
    return self[0] if self.size == 1
    real_s = [[s, 0].max, self.size - 1].min
    real_e = [[e, 0].max, self.size - 1].min
    s = [real_s, real_e].min
    e = [real_s, real_e].max
    return self[s] if s == e
    n = (e - s) + 1.0
    sort = self.sort
    return sort[((n - 1.0) / 2.0).floor] if rounded
    if (n % 2 == 1)
      return (sort[(n - 1.0) / 2.0]).to_f
    else
      return (sort[(n / 2.0) - 1.0] + sort[(n / 2.0)]) / 2.0
    end
  end
  #--------------------------------------------------------------------------
  # * covariance
  #--------------------------------------------------------------------------
  # Calcula la covariancia entre dos array del mismo tamaño.
  #--------------------------------------------------------------------------
  def Array.covariance(a, b)
    n = [a.size, b.size].min
    a = a[0...n] ; avera = a.average
    b = b[0...n] ; averb = b.average
    m = 0.0
    for i in 0...n
      m += ((a[i] - avera) * (b[i] - averb)) / (n - 1)
    end
    return m
  end
end

Eso es todo. Los scripts de Matrix y Hash Utils que también subí en este topic también se podrían actualizar pero creo que carecen de interés. Al menos al Array+ sí se le puede sacar alguna utilidad aunque sea puntual; a mí me ha servido un par de veces.
Saludos.
avatar
Wecoc
Administrador
Administrador



Créditos 12290

Gracias : 564

Volver arriba Ir abajo

Re: [RMXP/VX] [Herramienta de scripter] Array +

Mensaje por Contenido patrocinado


Contenido patrocinado


Volver arriba Ir abajo

Ver el tema anterior Ver el tema siguiente Volver arriba


Permisos de este foro:
No puedes responder a temas en este foro.