Tengo una matriz de estructuras y necesito mantenerlas únicas en función de un atributo, :num . Esta matriz se agregará con nuevos objetos de estructura. Si el nuevo objeto de estructura tiene un valor de atributo :num duplicado, quiero eliminar el elemento antiguo que contiene :num duplicado y reemplazarlo por el nuevo.
Esto es lo que quiero decir. Vamos a configurarlo:
Gen = Struct.new(:num, :val) arr = [] arr << Gen.new(11, "foo1") arr << Gen.new(12, "foo2") # [#<struct num=11, val="foo1">, #<struct num=12, val="foo2">]Luego lo alimento con nuevas estructuras. Vamos a construirlos:
s1 = Gen.new(12, "foo10") s2 = Gen.new(13, "foo3")arr << s1 , simplemente agregará s1 a arr .arr.uniq {|el| el.number} después de hacer lo anterior, a veces elimina "foo10", pero quiero mantener siempre la última estructura. Cuando s1 se agrega a arr , debe reemplazar la estructura anterior #<struct num=12, val="foo2"> porque s1 es el feed más nuevo. Dado que arr ya contiene :num 12, debemos reemplazarlo con la nueva estructura. Dado que s2 contiene un :num único, debería poder agregarse sin problema (incluso si s2 contiene un :val duplicado, no debería importar, solo me preocupa mantener :num único).
Al final, necesito que arr se vea como:
[#<struct num=11, val="foo1">, #<struct num=12, val="foo10">, #<struct num=13, val="foo3">]El orden de la matriz no importa.
Miré Agregar elemento a una matriz si aún no está allí , la condición de Ruby para insertar elementos únicos en una matriz , Eliminar elementos duplicados de la matriz en Ruby y algunas otras publicaciones. En su mayoría, se trata de una matriz simple, no de una matriz de estructuras.
¿Cómo puedo conseguir esto?
Es más fácil mantener un hash cuyas claves sean los valores de :num y cuyos valores sean la estructura asociada. El hash ( h ) se puede actualizar con una nueva estructura ( st ) de la manera deseada de la siguiente manera.
def add_struct(h, st) h.update(st[:num]=>st) endLuego, cuando se requiera una matriz de estructuras actuales, simplemente devuelva los valores del hash.
Consulte Hash#update (¡también conocido como merge! ). Recuerde que si los hashes h y g tienen una clave k , el valor de k en el hash h.update(g) (o h.merge(g) ) es igual a g[k] . h.update(st[:num]=>st) es la abreviatura de h.update({ st[:num]=>st }) . El valor de retorno de add_struct es el valor actualizado de h .
Aquí hay un ejemplo.
Gen = Struct.new(:num, :val) s1 = Gen.new(11, "foo1") #=> #<struct Gen num=11, val="foo1"> s2 = Gen.new(12, "foo2") #=> #<struct Gen num=12, val="foo2"> s3 = Gen.new(12, "foo10") #=> #<struct Gen num=12, val="foo10"> s4 = Gen.new(13, "foo3") #=> #<struct Gen num=13, val="foo3"> h = {} add_struct(h, s1) #=> {11=>#<struct Gen num=11, val="foo1">} add_struct(h, s2) #=> {11=>#<struct Gen num=11, val="foo1">, # 12=>#<struct Gen num=12, val="foo2">} add_struct(h, s3) #=> {11=>#<struct Gen num=11, val="foo1">, # 12=>#<struct Gen num=12, val="foo10">} add_struct(h, s4) #=> {11=>#<struct Gen num=11, val="foo1">, # 12=>#<struct Gen num=12, val="foo10">, # 13=>#<struct Gen num=13, val="foo3">} h #=> {11=>#<struct Gen num=11, val="foo1">, # 12=>#<struct Gen num=12, val="foo10">, # 13=>#<struct Gen num=13, val="foo3">} h.values #=> [#<struct Gen num=11, val="foo1">, # #<struct Gen num=12, val="foo10">, # #<struct Gen num=13, val="foo3">]Toma las nuevas gen una por una. Encuentre la generación anterior correspondiente y deje que tenga el valor de la nueva. Si no se encuentra una generación anterior, agregue la nueva generación completa.
Gen = Struct.new(:num, :val) arr = [] arr << Gen.new(11, "foo1") arr << Gen.new(12, "foo2") new_gens = [Gen.new(12, "foo10"), Gen.new(13, "foo3")] #let's go new_gens.each do |new_gen| match = arr.detect{|old_gen| old_gen.num == new_gen.num} match ? match.val = new_gen.val : arr << new_gen end p arr # =>[#<struct num=11, val="foo1">, #<struct num=12, val="foo10">, #<struct num=13, val="foo3">]