Dupliquer un tableau Ruby de chaînes
Question
arr = ["red","green","yellow"]
arr2 = arr.clone
arr2[0].replace("blue")
puts arr.inspect
puts arr2.inspect
produit:
["blue", "green", "yellow"]
["blue", "green", "yellow"]
Y at-il de toute façon à faire une copie complète d'un tableau de chaînes, autre que d'utiliser le maréchal que je comprends est un hack.
Je pourrais faire:
arr2 = []
arr.each do |e|
arr2 << e.clone
end
mais il ne semble pas très élégant, ni efficace.
Merci
La solution
Votre deuxième solution peut être raccourci à arr2 = arr.map do |e| e.dup end
(sauf si vous avez réellement besoin le comportement de clone
, il est recommandé d'utiliser dup
à la place).
Autre que vos deux solutions sont essentiellement les solutions standard pour effectuer une copie complète (bien que la deuxième version est seulement un niveau profond (si vous l'utilisez sur un tableau de tableaux de chaînes, vous pouvez toujours muter les cordes )). Il n'y a pas vraiment une façon plus agréable.
Edit: Voici une méthode deep_dup récursif qui fonctionne avec des tableaux imbriqués de façon arbitraire:
class Array
def deep_dup
map {|x| x.deep_dup}
end
end
class Object
def deep_dup
dup
end
end
class Numeric
# We need this because number.dup throws an exception
# We also need the same definition for Symbol, TrueClass and FalseClass
def deep_dup
self
end
end
Vous pouvez également définir deep_dup pour d'autres conteneurs (comme Hash), sinon vous aurez toujours une copie peu profonde pour ceux-ci.
Autres conseils
Je recommande votre idée initiale, mais un peu plus écrit de manière concise:
arr = ["red","green","yellow"]
arr2 = arr.inject([]) { |a,element| a << element.dup }
Je suis dans une situation similaire et très préoccupé par la vitesse. La façon la plus rapide pour moi était d'utiliser map{&:clone}
Donc, essayez ceci:
pry(main)> a = (10000..1000000).to_a.shuffle.map(&:to_s)
pry(main)> Benchmark.ms { b = a.deep_dup }
=> 660.7760030310601
pry(main)> Benchmark.ms { b = a.join("--!--").split("--!--") }
=> 605.0828141160309
pry(main)> Benchmark.ms { b = a.map(&:clone) }
=> 450.8283680770546
Vous pouvez faire une copie en profondeur de a
tableau par le code suivant:
Marshal.load(Marshal.dump(a))
Il semble si simple .. Il suffit d'exécuter le code ci-dessous:
a = [1,2,3]
b = [].replace(a)
b[1] = 5
puts a
puts b
Exécuter code ci-dessus et vous remarquerez la différence. Vive!
Vous pouvez utiliser ce hack:
arr1 = %w{ red green blue }
arr2 = arr1.join("--!--").split("--!--")
Mais il est juste pour le plaisir:)
arr2[0].replace("lol")
p arr1
#=> ["red", "green", "blue"]
p arr2
#=> ["lol", "green", "blue"]
Et il ne fonctionnera que pour 1 tableaux de niveau