How to stop shift from affecting other instances of an array - ruby

I need to shift through an array and keep a copy of the original array for future.
I tried creating another variable using a = b, but both are affected when I shift a.
rb(main):001:0> a = [1,2,3,4,5]
# => [1, 2, 3, 4, 5]
irb(main):002:0> b = a
# => [1, 2, 3, 4, 5]
irb(main):003:0> c = a.shift
# => 1
irb(main):004:0> a
# => [2, 3, 4, 5]
irb(main):005:0> b
# => [2, 3, 4, 5]
irb(main):006:0> c
# => 1
Is there a way to keep this from happening?

In Ruby it's important to remember variables are object references which behave a lot like pointers, so b = a does not make a copy, it is another reference to the same object.
To make a copy you must be explicit and use dup or clone to achieve this:
b = a.dup
If you're ever confused by Ruby's behaviour, stop and look at the objects you're dealing with:
a = [ 1 ]
b = a
a.object_id == b.object_id
# => true
They're exactly the same object, but when cloned:
b = a.dup
a.object_id == b.object_id
# => false
Now they're independent, at least on the top-level.
Note that this comes with some caveats, as this is only a shallow copy:
a = [ [ 1 ] ]
b = a.dup
b[0].object_id == a[0].object_id
# => true
This is where deep_clone tools come in handy if you need a complete clone, something available from various gems but most popularly ActiveSupport from Rails.
One thing you'll find in Ruby is it tends to steer towards a more functional style, as in if you wanted to strip an element from a and avoid mangling b:
a = [ 1, 2, 3, 4, 5 ]
b = a
a = a.drop(1)
# => [2, 3, 4, 5]
Where drop skips over the first N entries and returns the rest as a copy:
b
# => [1, 2, 3, 4, 5]

Related

Use of = vs .dup method

array = [1,2,3,4,5]
array1 = array
array2 = array.dup
puts array1 == array2
Why do we have a dup method when we can just assign to another variable?
array = [1,2,3,4,5]
array1 = array
array2 = array.dup
array << "aha"
p array1 # => [1, 2, 3, 4, 5, "aha"]
p array2 # => [1, 2, 3, 4, 5]
You're fooling yourself by:
Trying to reason from a single example.
Comparing the wrong things.
Array has its own == method that compares element by element so given:
a = [ 11 ]
b = [ 11 ]
then a == b is true even though a and b reference different arrays.
In general, = simply copies a reference similar to this in C:
int *i, *j;
i = j;
but dup makes a (shallow) copy.
If you compare the object_ids:
puts array1.object_id == array2.object_id
you'll see that the underlying array objects are different even though == says that the have equal contents.
A statement like:
array1 = array
just assigns a reference to array1 from array. This means that both array and array1 point to the same memory location. If you change the underlying array, it will be reflected in both copies:
irb(main):001:0> array = [1,2,3]
=> [1, 2, 3]
irb(main):002:0> array1 = array
=> [1, 2, 3]
irb(main):003:0> array
=> [1, 2, 3]
irb(main):004:0> array1
=> [1, 2, 3]
irb(main):005:0> array[0] = 10
=> 10
irb(main):006:0> array
=> [10, 2, 3]
irb(main):007:0> array1
=> [10, 2, 3]
If you use dup, it clones the underlying data, creating new, independent storage:
irb(main):008:0> array2 = array.dup
=> [10, 2, 3]
irb(main):009:0> array
=> [10, 2, 3]
irb(main):010:0> array2
=> [10, 2, 3]
irb(main):011:0> array2[0] = 20
=> 20
irb(main):012:0> array
=> [10, 2, 3]
irb(main):013:0> array2
=> [20, 2, 3]

How to remember swapped array elements in another array?

This is driving me crazy! I've been trying to write a Ruby method to find all permutations, to solve Project Euler's problem 24. When I swap the elements of an array, they are swapped properly. But when I try to STORE this swapped array in a DIFFERENT array, this new array only remembers the latest copy of my swapped array! It won't remember the older version.
When I print out a during the loop, it shows all permutations properly. But when I print out perm (which I use to store all different permutations of a), it only shows 1 version of a repeated several times. How do I fix this?
a = [0, 1, 2, 3]
perms = []
p "a = #{a}" # output: "a = [0, 1, 2, 3]"
perms << a # add a to perms array
p "perms = #{perms}" # output: "perms = [[0, 1, 2, 3]]"
a[0], a[1] = a[1], a[0] # swap 1st 2 elements of a
p "a = #{a}" # output: "a = [1, 0, 2, 3]"
perms << a # add a to perms array
p "perms = #{perms}" # "perms = [[1, 0, 2, 3], [1, 0, 2, 3]]"
a[1], a[2] = a[2], a[1] # swap 2nd 2 elements of a
p "a = #{a}" # "a = [1, 2, 0, 3]"
perms << a # add a to perms array
p "perms = #{perms}" # "perms = [[1, 2, 0, 3], [1, 2, 0, 3], [1, 2, 0, 3]]"
Thanks to Sawa below, both "dup" and "clone" methods solved my problem! Why doesn't my original way work? When would I use "dup" vs. "clone"? Please give me some code examples.
a[0], a[1] = a[1], a[0] # swap 1st 2 elements of a
p "a = #{a}" # output: "a = [1, 0, 2, 3]"
b = a.dup (or a.clone)
perms << b
p "perms = #{perms}" # "perms = [[0, 1, 2, 3], [1, 0, 2, 3]]" *** it remembers!
a[1], a[2] = a[2], a[1] # swap 2nd 2 elements of a
p "a = #{a}" # "a = [1, 2, 0, 3]"
b = a.dup (or a.clone)
perms << b
p "perms = #{perms}" # "perms = [[0, 1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3]]"
Variables in Ruby (with some exceptions, such as variables bound to integers) contain references to objects, not values. Here's an example from running "irb":
1.9.3p374 :021 > str1="hi"
=> "hi"
1.9.3p374 :022 > str2=str1
=> "hi"
1.9.3p374 :023 > str1.replace("world")
=> "world"
1.9.3p374 :024 > str2
=> "world"
You'll notice that once I replace the value for str1, str2's "value" changes as well. That's because it contains a reference to the str1 object. I know one difference between dup and clone has to do with the "freeze" method. If I had called str1.freeze, then it would prevent the object str1 references from being modified, e.g.,
1.9.3p374 :055 > str1.freeze
=> "hi"
1.9.3p374 :056 > str1[0]="b"
RuntimeError: can't modify frozen String
from (irb):56:in `[]='
from (irb):56
from /.rvm/rubies/ruby-1.9.3-p374/bin/irb:13:in `<main>
"Dup"-ing a frozen object doesn't create a frozen object whereas cloning does.
EDIT: just a slight update....When assigning an object on the right to a variable on the left (e.g., str = Object.new), the variable receives an object reference. When assigning one variable to another, the left-hand side variable receives a copy of the reference that the variable on the right contains. In either case, you are still storing object references in the left-hand side variable.
Your original didn't work because you kept modifying the same array instance a.
Take a dup of the original array each time before you modify it into a different array. Or, create a new instance of Array by not relying on a destructive method.
a = original_array
b = a.dup
... # do some modifications to `b`
perms << b
c = a.dup
... # do some modifications to `c`
perms << c
...
If you don't like reinventing the wheel, you can use the facets gem.
gem install facets
https://github.com/rubyworks/facets/blob/d96ec0d700d1d7180ccbb5452e0a926386ec0b32/lib/backport/facets/array/permutation.rb
require 'facets'
[1, 2, 3].permutation
#=> [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]

What is the difference of Ruby's Array#to_a method

For example:
a = [1,2,3,4]
b = a
c = a.to_a
a.insert(0,0) #=> [0,1,2,3,4]
b #=> [0,1,2,3,4]
c #=> [0,1,2,3,4]
Why the output of array b and c is the same? If I want to get a copy of array a, not a reference one, which method should I use?
Why the output of array b and c is the same?
Because all three local variables referencing the same objects,as below:
a = [1,2,3,4]
b = a
c = a.to_a
a.object_id
# => 72187200
b.object_id
# => 72187200
c.object_id
# => 72187200
If i want to get a copy of array a, not a reference one , which method should i use?
Then use a.dup.Here documented Object#dup
a = [1,2,3,4]
b = a.dup
c = a.dup
a.object_id
# => 82139270
b.object_id
# => 82139210
c.object_id
# => 82134600
a.insert(0,0) # => [0, 1, 2, 3, 4]
b # => [1, 2, 3, 4]
c # => [1, 2, 3, 4]
Array#to_a says : Returns self.If called on a subclass of Array, converts the receiver to an Array object.
So it will not be helpful as per your need.
This is because Array#to_a returns self, so both variables contain a reference to the same Array object. In order to get a new Array with the same contents, you can use either dup or clone (read about the differences between dup and clone):
a = [1, 2, 3]
b = a.dup
a << 4
a #=> [1, 2, 3, 4]
b #=> [1, 2, 3]
Note, however, that the same object references are stored in the new array. This means if you mutate the objects themselves they will still change in both arrays:
a = ['foo', 'bar']
b = a.dup
a[0] << 'baz'
a #=> ["foobaz", "bar"]
b #=> ["foobaz", "bar"]
This is because dup and clone are shallow-copies.
Array#to_a returns the receiver. That is why b and c refer to the same thing. Regarding why to_a returns the original array, in principle, it could be defined one or the other way, but I guess one use case for to_a is to apply it to a variable that is potentially nil to ensure it becomes an array.
some_value.to_a # => `[]` if `some_value` is `nil`
In such use case, you don't need to replace the array with another one in case the receiver is already an array. That would be performantly more preferable.
The reason for that is that variables are merely references to data. Variables are stored in memory; variables keep address of where they are located in a memory. So when you do:
a = b
Those two variables point to the same memory location, hence if you alter a, b is altered as well because it is the same object.
There are a few ways to force Ruby to create another copy of the object. The most popular one is the dup method mentioned by LBg. Note however that it is only creating a shallow copy. If you run:
a = ['foo','bar', []]
b = a.dup
a << 'blah'
b #=> ['foo', 'bar', []] as expected but
b[3] << blah
a #=> ['foobar', 'bar', ['blah]]
The reason for that is that array is in fact an array of references and nested array has not been duplicated when performing dup, so they are the same object.
To create a deep copy of an object, you can use the Marshall module:
b = Marshal.load(Marshal.dump(a))
However, usually you don't really need to do this. Also, some objects cannot be duplicated (e.g. symbols).
You can just do
b = a.dup
OLD POST
You can try this if there is no easier way
b = a.map {|x| x}
It works
1.9.3-p448 :001 > a = [1,2,3] => [1, 2, 3]
1.9.3-p448 :002 > b = a => [1, 2, 3]
1.9.3-p448 :003 > c = a.map{|x| x} => [1, 2, 3]
1.9.3-p448 :004 > a<<0 => [1, 2, 3, 0]
1.9.3-p448 :005 > b => [1, 2, 3, 0]
1.9.3-p448 :006 > c => [1, 2, 3]
But it is a shallow copy though.
According to this post, a.dup is the easier way.

why Hash value gets affected in Ruby

mainhash = { 'A' => [ 0,1,2,3,4 ] , 'B' => [ 0 ,1,2 ,3 ] }
ahash = mainhash['A']
indval = ahash.shift
ahash become as follows
[1, 2, 3, 4]
and mainhash become as follows
{"A"=>[1, 2, 3, 4], "B"=>[0, 1, 2, 3]}
I am manipulating ahash variable by shifting some values from ahash, When I do this operation it affects the mainhash value. Why it is happening?
Am I missing any conceptual understanding?
It's because ahash and mainhash both have references to the same Array instance. If you modify this through ahash, referenced object is being modified, so no wonder it changes also in mainhash.
To operate on copy (shallow copy, to be precise) of the object instead of the same object, you should use dup method:
ahash = mainhash['A'].dup
Look Array#shift
Removes the first element of self and returns it (shifting all other elements down by one). Returns nil if the array is empty.
mainhash = { 'A' => [ 0,1,2,3,4 ] , 'B' => [ 0 ,1,2 ,3 ] }
ahash = mainhash['A']
p ahash.object_id # => 8577888
p mainhash['A'].object_id # => 8577888
p indval = ahash.shift # => 0
As above seen, ahash and mainhash['A'] refer to the same Array object [ 0,1,2,3,4], thus changing ahash#shift causes 0 to be removed from ahash which also causes 0 to be removed from mainhash['A'].
Said that your Hash becomes as below :
mainhash
# => {"A"=>[1, 2, 3, 4], "B"=>[0, 1, 2, 3]}
All operations are legitimate and happened as documented to the link,I have given above.
How can I avoid affecting the mainhash
As #Marek Lipka said :
you should use dup method: ahash = mainhash['A'].dup.
mainhash = { 'A' => [ 0,1,2,3,4 ] , 'B' => [ 0 ,1,2 ,3 ] }
ahash = mainhash['A'].dup
ahash.object_id # => 8577516
mainhash['A'].object_id # => 8577600
indval = ahash.shift # => 0
ahash # => [1, 2, 3, 4]
mainhash['A'] # => [0, 1, 2, 3, 4]
Why it is happening ?.
arr = [1, 2, 3]
x = arr
arr.shift
p arr
p x
--output:--
[2, 3]
[2, 3]
arr and x both refer to the same array. Assignment ('=') does not create a copy.
Now look at this code:
arr = [1, 2, 3]
x = arr.dup
arr.shift
p arr
p x
--output:--
[2, 3]
[1, 2, 3]
And by the way, the name 'ahash' is a terrible name for an array.

What kind of variable is ARGV in ruby?

From what I have read ARGV should be a constant since it is all uppercase, but I was able to write a quick program that changed one of the values in ARGV without error. So what type of variable is ARGV?
p ARGV
ARGV[0] = "Not the orginal"
p ARGV
ARGV is an array. Keep in mind that "constant" just means that the variable shouldn't be reassigned, not that the object itself can't change. You may be confusing it with the idea of a const object in C++. That is more equivalent to a frozen object in Ruby. (And note that even "constants shouldn't be reassigned" is a weak guarantee in Ruby. Reassigning a constant doesn't fail; it just prints a warning. It is a bad practice, though.)
To illustrate the difference:
ruby-1.9.2-p0 > CONSTANT = [1,2,3]
=> [1, 2, 3]
ruby-1.9.2-p0 > frozen = [1,2,3].freeze
=> [1, 2, 3]
ruby-1.9.2-p0 > CONSTANT << 4
=> [1, 2, 3, 4]
ruby-1.9.2-p0 > frozen << 4
RuntimeError: can't modify frozen array
ARGV is a constant, but it's an Array. Values in a constant array can be freely changed without any warnings, like any usual array element.
irb(main)> ARGV.class
=> Array
irb(main)> QWERTY = [1, 2, 3, 4]
=> [1, 2, 3, 4]
irb(main)> QWERTY[1] = 5
=> 5
irb(main)> QWERTY
=> [1, 5, 3, 4]
irb(main)> QWERTY << 6
=> [1, 5, 3, 4, 6]
irb(main)> QWERTY = 3
(irb): warning: already initialized constant QWERTY
=> 3

Resources