Problem with copying array

Discussion in 'Ruby' started by jbieger@gmail.com, Dec 24, 2007.

  1. Guest

    Hi, I'm a total newbie with Ruby and I was trying to make this
    function that would get a (multidimensional) array, make a copy, make
    some changes to the copy and then return the copy, without altering
    the original array. However, no matter what I try, the original array
    gets altered. Here is my code:

    def prune_times (times)
    # copy = times
    # copy = Array.new(times)
    # copy = times.clone
    copy = times.dup
    copy.each do |map|
    map.each do |task|
    task.replace(best_n(task, 2))
    end
    end
    return copy
    end

    Any help would be greatly appreciated!

    Jordi
    , Dec 24, 2007
    #1
    1. Advertising

  2. What's your array an array of? Array.dup will copy the array to a new
    array, but if the values in the array are references to some class
    you're using, it'll be a different array of the same items.
    Primitives would be copied correctly. You need to do your own deep
    copy if it's a more complicated array value.

    -Bryan

    On Dec 24, 2007, at 7:19 AM, wrote:

    > Hi, I'm a total newbie with Ruby and I was trying to make this
    > function that would get a (multidimensional) array, make a copy, make
    > some changes to the copy and then return the copy, without altering
    > the original array. However, no matter what I try, the original array
    > gets altered. Here is my code:
    >
    > def prune_times (times)
    > # copy = times
    > # copy = Array.new(times)
    > # copy = times.clone
    > copy = times.dup
    > copy.each do |map|
    > map.each do |task|
    > task.replace(best_n(task, 2))
    > end
    > end
    > return copy
    > end
    >
    > Any help would be greatly appreciated!
    >
    > Jordi
    >
    Bryan Duxbury, Dec 24, 2007
    #2
    1. Advertising

  3. Guest

    Thanks for your reply!

    Like I said, it's a multidimensional array, so I suppose that the
    contents aren't primitive and I need to do as you suggested. Is there
    a built-in function for this, or do I need to make my own. It seems
    like a pretty common operation...

    Jordi

    On 24 dec, 16:50, Bryan Duxbury <> wrote:
    > What's your array an array of? Array.dup will copy the array to a new
    > array, but if the values in the array are references to some class
    > you're using, it'll be a different array of the same items.
    > Primitives would be copied correctly. You need to do your own deep
    > copy if it's a more complicated array value.
    >
    > -Bryan
    >
    > On Dec 24, 2007, at 7:19 AM, wrote:
    >
    > > Hi, I'm a total newbie with Ruby and I was trying to make this
    > > function that would get a (multidimensional) array, make a copy, make
    > > some changes to the copy and then return the copy, without altering
    > > the original array. However, no matter what I try, the original array
    > > gets altered. Here is my code:

    >
    > > def prune_times (times)
    > > # copy = times
    > > # copy = Array.new(times)
    > > # copy = times.clone
    > > copy = times.dup
    > > copy.each do |map|
    > > map.each do |task|
    > > task.replace(best_n(task, 2))
    > > end
    > > end
    > > return copy
    > > end

    >
    > > Any help would be greatly appreciated!

    >
    > > Jordi
    , Dec 24, 2007
    #3
  4. On 24 Dec 2007, at 16:05, wrote:

    > Thanks for your reply!
    >
    > Like I said, it's a multidimensional array, so I suppose that the
    > contents aren't primitive and I need to do as you suggested. Is there
    > a built-in function for this, or do I need to make my own. It seems
    > like a pretty common operation...


    You need to do it yourself. It may be pretty common, but the exact
    specifics of how deep to go etc... tend to be rather application
    dependant.

    Fred
    >
    >
    > Jordi
    >
    > On 24 dec, 16:50, Bryan Duxbury <> wrote:
    >> What's your array an array of? Array.dup will copy the array to a new
    >> array, but if the values in the array are references to some class
    >> you're using, it'll be a different array of the same items.
    >> Primitives would be copied correctly. You need to do your own deep
    >> copy if it's a more complicated array value.
    >>
    >> -Bryan
    >>
    >> On Dec 24, 2007, at 7:19 AM, wrote:
    >>
    >>> Hi, I'm a total newbie with Ruby and I was trying to make this
    >>> function that would get a (multidimensional) array, make a copy,
    >>> make
    >>> some changes to the copy and then return the copy, without altering
    >>> the original array. However, no matter what I try, the original
    >>> array
    >>> gets altered. Here is my code:

    >>
    >>> def prune_times (times)
    >>> # copy = times
    >>> # copy = Array.new(times)
    >>> # copy = times.clone
    >>> copy = times.dup
    >>> copy.each do |map|
    >>> map.each do |task|
    >>> task.replace(best_n(task, 2))
    >>> end
    >>> end
    >>> return copy
    >>> end

    >>
    >>> Any help would be greatly appreciated!

    >>
    >>> Jordi

    >
    >
    Frederick Cheung, Dec 24, 2007
    #4
  5. wrote:
    > Thanks for your reply!
    >
    > Like I said, it's a multidimensional array, so I suppose that the
    > contents aren't primitive and I need to do as you suggested. Is there
    > a built-in function for this, or do I need to make my own. It seems
    > like a pretty common operation...
    >
    > Jordi
    >
    > On 24 dec, 16:50, Bryan Duxbury <> wrote:
    >
    >> What's your array an array of? Array.dup will copy the array to a new
    >> array, but if the values in the array are references to some class
    >> you're using, it'll be a different array of the same items.
    >> Primitives would be copied correctly. You need to do your own deep
    >> copy if it's a more complicated array value.
    >>
    >> -Bryan
    >>
    >> On Dec 24, 2007, at 7:19 AM, wrote:
    >>
    >>
    >>> Hi, I'm a total newbie with Ruby and I was trying to make this
    >>> function that would get a (multidimensional) array, make a copy, make
    >>> some changes to the copy and then return the copy, without altering
    >>> the original array. However, no matter what I try, the original array
    >>> gets altered. Here is my code:
    >>>
    >>> def prune_times (times)
    >>> # copy = times
    >>> # copy = Array.new(times)
    >>> # copy = times.clone
    >>> copy = times.dup
    >>> copy.each do |map|
    >>> map.each do |task|
    >>> task.replace(best_n(task, 2))
    >>> end
    >>> end
    >>> return copy
    >>> end
    >>>
    >>> Any help would be greatly appreciated!
    >>>
    >>> Jordi
    >>>

    >
    >
    >
    >

    Your methods of copying the array are correct (though, you should remove
    one and only use the other, which ever). The problem is that with some
    objects, Ruby doesn't know how to "copy" them.

    Bryan already mentioned this, but for primitives like strings, integers,
    floats and whatnot, Ruby knows how to copy these objects, but if you
    have custom classes or other classes that don't define their own
    behavior for copying, then Ruby will keep the reference.

    Hope that helps.

    --
    Matthew Harris
    http://matthewharris.org
    Matthew Harris, Dec 24, 2007
    #5
  6. Ryan Davis Guest

    On Dec 24, 2007, at 07:19 , wrote:

    > Hi, I'm a total newbie with Ruby and I was trying to make this
    > function that would get a (multidimensional) array, make a copy, make
    > some changes to the copy and then return the copy, without altering
    > the original array. However, no matter what I try, the original array
    > gets altered. Here is my code:


    `ri Enumerable#map`
    Ryan Davis, Dec 24, 2007
    #6
  7. Matthew Harris wrote:
    > Bryan already mentioned this, but for primitives like strings, integers,
    > floats and whatnot, Ruby knows how to copy these objects


    Strings can be copied with the dup method, yes. But if you mean to imply that
    that happens automatically when dupping an array of Strings, you are wrong:
    >> arr=["chunky", "bacon"]
    >> arr.dup.each {|str| str.tr!("ck","kc")}
    >> arr

    => ["khuncy", "bakon"]

    Integers and Floats can not be copied at all:
    >> 5.dup

    TypeError: can't dup Fixnum

    >> 5.0.dup

    TypeError: allocator undefined for Float

    > but if you
    > have custom classes or other classes that don't define their own
    > behavior for copying, then Ruby will keep the reference.


    If you dup an array you will always get a new array with references to the old
    objects. dup never makes a deep copy.
    Presumably there is no built-in way to make a deep copy because, as mentioned
    above, some objects (like Integers) can't be copied.


    I hope this cleared the confusion a bit,
    Sebastian
    --
    Jabber:
    ICQ: 205544826
    Sebastian Hungerecker, Dec 25, 2007
    #7
  8. Bryan Duxbury wrote:
    > What's your array an array of? Array.dup will copy the array to a new
    > array, but if the values in the array are references to some class
    > you're using, it'll be a different array of the same items.
    > Primitives would be copied correctly. You need to do your own deep
    > copy if it's a more complicated array value.


    a) There are no primitives in ruby. Everything is an object.
    b) Array#dup never makes a deep copy. You'll always get a different array of
    the same items no matter what the class of these items is.


    HTH,
    Sebastian
    --
    Jabber:
    ICQ: 205544826
    Sebastian Hungerecker, Dec 25, 2007
    #8
  9. Jan Dvorak Guest

    On Monday 24 December 2007 16:19:59 wrote:
    > Hi, I'm a total newbie with Ruby and I was trying to make this
    > function that would get a (multidimensional) array, make a copy, make
    > some changes to the copy and then return the copy, without altering
    > the original array. However, no matter what I try, the original array
    > gets altered. Here is my code:


    Another possibility is serialization - it's still your job to make your
    classes serializable and there is stuff that cannot be serialized, but for
    simple cases (multi-dimensional arrays) it works out-of-box:

    irb(main):001:0> a = [["a","b"],[1,2]]
    => [["a", "b"], [1, 2]]
    irb(main):002:0> b = Marshal.load(Marshal.dump(a))
    => [["a", "b"], [1, 2]]
    irb(main):003:0> b[0][0], b[1][0] = "x", 9
    => ["x", 9]
    irb(main):004:0> a
    => [["a", "b"], [1, 2]]
    irb(main):005:0> b
    => [["x", "b"], [9, 2]]

    Jan
    Jan Dvorak, Dec 25, 2007
    #9
  10. Alan Slater Guest

    Highly related newbie question, please pardon the non-technical
    language.

    So, arrays (even arrays of 'primitives' like strings) don't actually
    contain the objects that fill each entry, they instead (effectively)
    link to those objects. So, .delete_at and .slice! (for example) don't
    remove things from the array, they delete the objects that are being
    linked to completely.

    This explains my problem (why, whenever I delete an entry from an array,
    it also deletes it from every copy of the array).

    So, how could I simply remove an object from an array, without deleting
    the object itself? Something like, array_name.remove_at(x) (except
    obviously that doesn't exist).

    I've been through the API and can't find anything that seems to fit. I
    tried array_name[x] = nil, but that just left an empty entry and didn't
    change the length of the array. Even that seems to change the original
    object to nil too, as following array_name[x] = nil with
    array.delete_at(x) removes the equivalent entry from the original array
    as well.

    How can I remove an entry from an array without deleting the object that
    the entry refers to?
    --
    Posted via http://www.ruby-forum.com/.
    Alan Slater, Oct 30, 2008
    #10
  11. Hi --

    On Fri, 31 Oct 2008, Alan Slater wrote:

    > Highly related newbie question, please pardon the non-technical
    > language.
    >
    > So, arrays (even arrays of 'primitives' like strings) don't actually
    > contain the objects that fill each entry, they instead (effectively)
    > link to those objects. So, .delete_at and .slice! (for example) don't
    > remove things from the array, they delete the objects that are being
    > linked to completely.
    >
    > This explains my problem (why, whenever I delete an entry from an array,
    > it also deletes it from every copy of the array).
    >
    > So, how could I simply remove an object from an array, without deleting
    > the object itself? Something like, array_name.remove_at(x) (except
    > obviously that doesn't exist).
    >
    > I've been through the API and can't find anything that seems to fit. I
    > tried array_name[x] = nil, but that just left an empty entry and didn't
    > change the length of the array. Even that seems to change the original
    > object to nil too, as following array_name[x] = nil with
    > array.delete_at(x) removes the equivalent entry from the original array
    > as well.
    >
    > How can I remove an entry from an array without deleting the object that
    > the entry refers to?


    Removing an entry from an array never destroys the object.


    s = "string"
    a =
    a.clear
    p a # []
    p s # "string"

    As long as a reference to the object exists, the object will still be
    available. Objects don't even know whether or not they are in
    collections.


    David

    --
    Rails training from David A. Black and Ruby Power and Light:
    Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL
    Advancing with Rails January 19-22 Fort Lauderdale, FL *
    * Co-taught with Patrick Ewing!
    See http://www.rubypal.com for details and updates!
    David A. Black, Oct 30, 2008
    #11
  12. Alan Slater wrote:
    > arrays (even arrays of 'primitives' like strings) don't actually
    > contain the objects that fill each entry, they instead (effectively)
    > link to those objects.


    Yes - they contain references to objects.

    > So, .delete_at and .slice! (for example) don't
    > remove things from the array, they delete the objects that are being
    > linked to completely.


    No - they delete the references from the array.

    The objects themselves are unchanged. If there are other references to
    them elsewhere in the system, they will live on. If the array element
    was the only reference to the object, so that there are no more now,
    then at some point in the future the object will be garbage-collected.

    > This explains my problem (why, whenever I delete an entry from an array,
    > it also deletes it from every copy of the array).


    No - you are deleting from a single array, but you have multiple
    references to that array from other places, so they all see the same
    changed array.

    A good way to probe this is with the 'object_id' method.

    irb(main):001:0> a = [[1,2,3],[4,5,6]]
    => [[1, 2, 3], [4, 5, 6]]
    irb(main):002:0> a.object_id
    => -605380508
    irb(main):003:0> a[0].object_id
    => -605380598
    irb(main):004:0> a[1].object_id
    => -605380608
    irb(main):005:0> b = a.dup
    => [[1, 2, 3], [4, 5, 6]]
    irb(main):006:0> b.object_id
    => -605417698
    irb(main):007:0> b[0].object_id
    => -605380598
    irb(main):008:0> b[1].object_id
    => -605380608

    You can see that a and b are different objects, but a[0] and b[0] point
    to the same object (ditto a[1] and b[1]). Diagramatically:

    a -----> [ . , . ]
    | |
    v v
    [1,2,3] [4,5,6]
    ^ ^
    | |
    b -----> [ . , . ]

    The sub-arrays don't belong to 'a' any more than they belong to 'b'. So
    the consequence is:

    irb(main):009:0> a[0] << 99
    => [1, 2, 3, 99]
    irb(main):010:0> a
    => [[1, 2, 3, 99], [4, 5, 6]]
    irb(main):011:0> b
    => [[1, 2, 3, 99], [4, 5, 6]]

    However if you make a modification to one of the outer arrays, e.g. by
    adding or removing an element, this is fine:

    irb(main):012:0> a << [7,8,9]
    => [[1, 2, 3, 99], [4, 5, 6], [7, 8, 9]]
    irb(main):013:0> a
    => [[1, 2, 3, 99], [4, 5, 6], [7, 8, 9]]
    irb(main):014:0> b
    => [[1, 2, 3, 99], [4, 5, 6]]

    > So, how could I simply remove an object from an array, without deleting
    > the object itself?


    slice! or delete_at

    Regards,

    Brian.
    --
    Posted via http://www.ruby-forum.com/.
    Brian Candler, Oct 30, 2008
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. MiniDisc_2k2

    Re: array copying to another array

    MiniDisc_2k2, Jul 13, 2003, in forum: C++
    Replies:
    1
    Views:
    348
    Philip Lawatsch
    Jul 13, 2003
  2. John Harrison

    Re: array copying to another array

    John Harrison, Jul 13, 2003, in forum: C++
    Replies:
    2
    Views:
    395
    John Harrison
    Jul 15, 2003
  3. Thomas Matthews

    Re: array copying to another array

    Thomas Matthews, Jul 13, 2003, in forum: C++
    Replies:
    0
    Views:
    369
    Thomas Matthews
    Jul 13, 2003
  4. DaTurk
    Replies:
    2
    Views:
    365
    Jim Langston
    Sep 11, 2007
  5. janus

    Copying one array to another array

    janus, Feb 3, 2010, in forum: C Programming
    Replies:
    16
    Views:
    648
    Peter Nilsson
    Feb 3, 2010
Loading...

Share This Page