Why don't numbers support .dup?
Most objects in Ruby are passed by reference and can be dupped. Eg:
s = "Hello"
t = s # s & t reference to the same string
t.upcase! # modifying either one will affect the other
s # ==> "HELLO"
A few objects in Ruby are immediate, though. They are passed by value, there can only be one of this value and it therefore cannot be duped. These are any (small) integers, true
, false
, symbols and nil
. Many floats are also immediates in Ruby 2.0 on 64 bit systems.
In this (preposterous) example, any "42" will hold the same instance variable.
class Fixnum
attr_accessor :name
alias_method :original_to_s, :to_s
def to_s
name || original_to_s
end
end
42.name = "The Answer"
puts *41..43 # => 41, The Answer, 43
Since you would normally expect something.dup.name = "new name"
to not affect any other object than the copy obtained with dup
, Ruby chooses not to define dup
on immediates.
Your question is more complex than it appears. There was some discussion on ruby-core as to how this can be made easier. Also, other types of Numeric objects (floats, bignums, rationals and complex numbers) can not be duped although they are not immediates either.
Note that ActiveSupport (part of rails) provide the method duplicable?
on all objects
Can someone explain what dup() in C does?
Just wanted to respond to myself on the second question after experimenting a bit.
The answer is YES. A file descriptor that you make can take a value 0, 1, 2 if stdin, stdout or stderr are closed.
Example:
close(1); //closing stdout
newfd=dup(1); //newfd takes value of least available fd number
Where this happens to file descriptors:
0 stdin .--------------. 0 stdin .--------------. 0 stdin
1 stdout =| close(1) :=> 2 stderr =| newfd=dup(1) :=> 1 newfd
2 stderr '--------------' '--------------' 2 stderr
Duplicate a floating point number with Ruby in Sketchup
I can't see what your updated question has to do with the original one, but here's two ways to do what you wanted:
b = [a.dup, b.dup]
b[0][1] += 1.1
b[1][1] += 1.1
or
b.map! { |r| r.dup.tap { |r2| r2[1] += 1.1 } }
When to use dup, and when to use clone in Ruby?
It is true that clone
copies the frozen
state of an object, while dup
does not:
o = Object.new
o.freeze
o.clone.frozen?
#=> true
o.dup.frozen?
#=> false
clone
will also copy the singleton methods of the object while dup
does not:
o = Object.new
def o.foo
42
end
o.clone.respond_to?(:foo)
#=> true
o.dup.respond_to?(:foo)
#=> false
Which leads me to the assumption that clone
is sometimes understood as to provide a "deeper" copy than dup
. Here are some quotes about the topic:
Comment on ActiveRecord::Base#initialize_dup
from Rails 3:
Duped objects have no id assigned and are treated as new records. Note
that this is a "shallow" copy as it copies the object's attributes
only, not its associations. The extent of a "deep" copy is application
specific and is therefore left to the application to implement according
to its need.
An article about deep copies in Ruby:
There is another method worth mentioning,
clone
. Theclone
method does the same thing asdup
with one important distinction: it's expected that objects will override this method with one that can do deep copies.
But then again, theres deep_dup
in Rails 4:
Returns a deep copy of object if it's duplicable. If it's not duplicable, returns
self
.
and also ActiveRecord::Core#dup
and #clone
in Rails 4:
clone
— Identical to Ruby's clone method. This is a "shallow" copy. Be warned that your attributes are not copied. [...] If you need a copy of your attributes hash, please use the#dup
method.
Which means that here, the word dup
is used to refer to a deep clone again. As far as I can see, there seems to be no consensus in the community, except that you should use clone
and dup
in the case when you need a specific side effect of either one.
Finally, I see dup
much more often in Ruby code than clone
. I have never used clone
so far, and I won't until I explicitly need to.
Original variable still changes with .clone or .dup
A dup
or clone
in Ruby is a shallow clone, meaning that only the outer object is cloned, not its children. In your case, this means that the couples
array is copied, but not each individual couple.
If you want it to be a deep clone, you need to do it manually for the stdlib arrays:
new_couples = original_couples.map { |couple| couple.clone }
If you are in a domain where copies of collections are often necessary, or you are trying to work in a more functional style, I suggest you take a look at the Hamster
gem, that brings immutable data structures to ruby.
Fastest way to duplicate an array in JavaScript - slice vs. 'for' loop
There are at least 6 (!) ways to clone an array:
- loop
- slice
- Array.from()
- concat
- spread operator (FASTEST)
- map
A.map(function(e){return e;});
There has been a huuuge BENCHMARKS thread, providing following information:
for blink browsers
slice()
is the fastest method,concat()
is a bit slower, andwhile loop
is 2.4x slower.for other browsers
while loop
is the fastest method, since those browsers don't have internal optimizations forslice
andconcat
.
This remains true in Jul 2016.
Below are simple scripts that you can copy-paste into your browser's console and run several times to see the picture. They output milliseconds, lower is better.
while loop
n = 1000*1000;
start = + new Date();
a = Array(n);
b = Array(n);
i = a.length;
while(i--) b[i] = a[i];
console.log(new Date() - start);
slice
n = 1000*1000;
start = + new Date();
a = Array(n);
b = a.slice();
console.log(new Date() - start);
Please note that these methods will clone the Array object itself, array contents however are copied by reference and are not deep cloned.
origAr == clonedArr //returns false
origAr[0] == clonedArr[0] //returns true
Methods to create deep copy of objects without the help of Marshal
This solution works
class CashRegister
attr_accessor :bills
def initialize
@bills = []
end
def clone
cloned = super
cloned.bills = @bills.map { |bill| bill.clone }
cloned
end
end
class Bill
attr_accessor :positions
def initialize(nr)
@nr = nr
@positions = []
end
def clone
cloned = super
cloned.positions = @positions.map{ |pos| pos.clone }
cloned
end
end
class Position
attr_reader :price
attr_writer :product
# this method is given
def product
@product.clone
end
def initialize(product, price)
@product = product
@price = price
end
def clone
cloned = super
cloned.product = product
cloned
end
end
Use [].replace to make a copy of an array
This is the tricky concept of mutability in ruby. In terms of core objects, this usually comes up with arrays and hashes. Strings are mutable as well, but this can be disabled with a flag at the top of the script. See What does the comment "frozen_string_literal: true" do?.
In this case, you can call dup
, deep_dup
, clone
easily to the same effect as replace
:
['some', 'array'].dup
['some', 'array'].deep_dup
['some', 'array'].clone
Marshal.load Marshal::dump(['some', 'array'])
In terms of differences, dup
and clone
are the same except for some nuanced details - see What's the difference between Ruby's dup and clone methods?
The difference between these and deep_dup
is that deep_dup
works recursively. For example if you dup a nested array, the inner array will not be cloned:
a = [[1]]
b = a.clone
b[0][0] = 2
a # => [[2]]
The same thing happens with hashes.
Marshal.load Marshal::dump <object>
is a general approach to deep cloning objects, which, unlike deep_dup
, is in ruby core. Marshal::dump
returns a string so it can be handy in serializing objects to file.
If you want to avoid unexpected errors like this, keep a mental index of which methods have side-effects and only call those when it makes sense to. An explanation point at the end of a method name indicates that it has side effects, but others include unshift, push, concat, delete, and pop. A big part of fuctional programming is avoiding side effects. You can see https://www.sitepoint.com/functional-programming-techniques-with-ruby-part-i/
lodash: Get duplicate values from an array
You can use this:
_.filter(arr, (val, i, iteratee) => _.includes(iteratee, val, i + 1))
Note that if a number appears more than two times in your array you can always use _.uniq
.
Related Topics
How Do Version Numbers Work for Mri Ruby
Automatically Open a File as Binary with Ruby
Cannot Assign Requested Address - Bind(2) (Errno::Eaddrnotavail)
How to Use Same Browser Window for Automated Test Using Selenium-Webdriver (Ruby)
Retrieve Number from the String Pattern Using Regular Expression
Is There a Best Directory to Place Image Uploads on Heroku
Getting Headers from a Ruby Net::Http Request Before Making the Request
Bootstrap Datepicker Default Value Simple_Form_For
What Is the Opposite of Ruby's Include
Save All Image Files from a Website
Rails/Ruby Error When Creating Database: Unable to Load the Eventmachine C Extension
How to Make Id a Random 8 Digit Alphanumeric in Rails
Encoding::Undefinedconversionerror: "\Xe4" from Ascii-8Bit to Utf-8
Ruby What Class Gets a Method When There Is No Explicit Receiver