Duplizieren eines Rubin Array von Strings
Frage
arr = ["red","green","yellow"]
arr2 = arr.clone
arr2[0].replace("blue")
puts arr.inspect
puts arr2.inspect
erzeugt:
["blue", "green", "yellow"]
["blue", "green", "yellow"]
Gibt es trotzdem eine tiefe Kopie eines Arrays von Strings zu tun, andere als die Verwendung von Marschall, wie ich verstehen, dass ein Hack.
ich tun konnte:
arr2 = []
arr.each do |e|
arr2 << e.clone
end
aber nicht sehr elegant erscheinen, oder effizient.
Danke
Lösung
Ihre zweite Lösung kann auf arr2 = arr.map do |e| e.dup end
verkürzt werden (es sei denn, Sie tatsächlich das Verhalten von clone
brauchen, es zu benutzen dup
empfohlen wird statt).
Anders als das Ihre beiden Lösungen sind im Grunde die Standardlösungen eine tiefe Kopie auszuführen (wenn auch die zweite Version nur eine Ebene tief ist (dh, wenn Sie es auf einem Array von Arrays von Strings verwenden, können Sie immer noch die Saiten mutieren )). Es ist nicht wirklich ein schöner Weg.
Edit: Hier ist eine rekursive deep_dup Methode, dass die Arbeiten mit beliebig verschachtelt Arrays:
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
Sie möchten vielleicht auch für andere Behälter definieren deep_dup (wie Hash), sonst werden Sie noch eine flache Kopie für diejenigen erhalten.
Andere Tipps
ich Ihre Idee empfehlen, aber etwas prägnanter geschrieben:
arr = ["red","green","yellow"]
arr2 = arr.inject([]) { |a,element| a << element.dup }
Ich bin in einer ähnlichen Situation und sehr besorgt über die Geschwindigkeit. Der schnellste Weg für mich war zu Verwendung von map{&:clone}
machen
So versuchen Sie dies:
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
Sie können von folgendem Code eine tiefe Kopie des Arrays a
machen:
Marshal.load(Marshal.dump(a))
Es sieht so einfach .. Nur die folgenden Code ausführen:
a = [1,2,3]
b = [].replace(a)
b[1] = 5
puts a
puts b
Ausführen obigen Code, und Sie werden den Unterschied bemerken. Cheers!
Sie können diesen Hack verwenden:
arr1 = %w{ red green blue }
arr2 = arr1.join("--!--").split("--!--")
Aber es ist nur zum Spaß:)
arr2[0].replace("lol")
p arr1
#=> ["red", "green", "blue"]
p arr2
#=> ["lol", "green", "blue"]
Und es wird nur für 1 Level-Arrays arbeiten