Copying one object array to another including all it's properties

edited December 2014 in Programming Questions

I have a 2 dimensional object array and I want to set one of the array values objects equal to a previous one including all it's properties

I want to set:

    for (int k=0; k<n; k++)
    objectArray[j][k]=objectArray[j-1][k]

I tried the above but it seems to set all objectArray objects to have the same property values ie objectArray[j-2][k] now equals objectArray[j][k] as well?? Not sure why.

The following works.

for (int k=0; k<n; k++) {
  objectArray[j][k].propertyA=objectArray[j-1][k].propertyA
    objectArray[j][k].propertyB=objectArray[j-1][k].propertyB
    objectArray[j][k].propertyC=objectArray[j-1][k].propertyC     // etc
}

But do I really have to copy all properties to get this to work?

Thanks

Answers

  • edited December 2014

    If you intend to right-shift the whole array, you should save current index's element before replacing it w/ the 1 from its left. Otherwise, everything's gonna be the head index element! :-SS

    Also if you wanna shorten the array by removing its head, you should apply subset() before start:
    https://processing.org/reference/subset_.html

    But 1 more important point is that you're only shifting the array's outer dimension.
    Hence no need to touch its other inner dimensions. That's 1 less huge problem to deal w/: :bz

    // forum.processing.org/two/discussion/8477/
    // copying-one-object-array-to-another-including-all-it039s-properties
    
    static final int ROWS = 3, COLS = 2;
    PVector[][] vecs = new PVector[ROWS][COLS];
    
    void setup() {
      println("Array Right-shifting:\n");
    
      for (PVector[] row : vecs) {
        for (int i = 0; i != COLS; row[i++] = PVector.random3D(this));
        println(row);
      }
      println("Length: #", vecs.length, '\n');
    
      rightShift(false);
      println("Length: #", vecs.length, '\n');
    
      rightShift(false);
      println("Length: #", vecs.length);
    
      exit();
    }
    
    void rightShift(boolean toShorten) {
      PVector[] now, old = vecs.length > 0? vecs[0] : null;
      if (toShorten & vecs.length > 0)  vecs = (PVector[][]) subset(vecs, 1);
    
      for (int i = 0; i != vecs.length
        ; now = vecs[i], println( vecs[i++] = old ), old = now);
    }
    

    Alternatively, you can choose left-shifting. Which btW is much more common: =:)

    // forum.processing.org/two/discussion/8477/
    // copying-one-object-array-to-another-including-all-it039s-properties
    
    static final int ROWS = 3, COLS = 2;
    PVector[][] vecs = new PVector[ROWS][COLS];
    
    void setup() {
      println("Array Left-shifting:\n");
    
      for (PVector[] row : vecs) {
        for (int i = 0; i != COLS; row[i++] = PVector.random3D(this));
        println(row);
      }
      println("Length: #", vecs.length, '\n');
    
      leftShift(false);
      println("Length: #", vecs.length, '\n');
    
      leftShift(false);
      println("Length: #", vecs.length);
    
      exit();
    }
    
    void leftShift(boolean toShorten) {
      PVector[] now, old = vecs.length > 0? vecs[vecs.length-1] : null;
      if (toShorten & vecs.length > 0)  vecs = (PVector[][]) shorten(vecs);
    
      for (int i = vecs.length; i-- != 0
        ; now = vecs[i], vecs[i] = old, old = now);
    
      for (PVector[] row : vecs)  println(row);
    }
    
  • But do I really have to copy all properties to get this to work?

    Technically yes but there are better ways to do it.

    Before I show you how, I need to explain the difference between an object reference and an object.

    Consider the following code

    Foo f1, f2;
    
    void setup() {
      f1 = new Foo(5,3);
      f1.show("f1");
      f2 = f1;
      f2.show("f2");
      f1.a = -99;
      f2.show("f2");  
    }
    
    class Foo {
      int a;
      int b;
    
      Foo(int p0, int p1) {
        a = p0;
        b = p1;
      }
    
      void show(String id) {
        println(id," = [", a, ",", b, "]");
      }
    }
    

    In line 1 we have declared 2 object references of type Foo (f1 and f2) Java will initialise these to null. We have no objects yet - all objects are created with the new command so the one and only object is created in line 4.

    In line 6 we have f2 = f1 and many newbies think they are copying the object f1 and 'storing it' in f2. This is not true this statement simply copies the object reference.

    The output from this program is

    f1  = [ 5 , 3 ]
    f2  = [ 5 , 3 ]
    f2  = [ -99 , 3 ]
    

    Notice that changing a field in f0 (line 8) affects f2. That is because both f1 and f2 reference the same object. In many cases this is the desired outcome but if you want an independent copy (i.e. a second object) then you need to do something more.

    There are different ways of getting an exact copy of an object and the method I demonstrate here is probably the simplest and uses a copy constructor.

    Foo f1, f2;
    
    void setup() {
      f1 = new Foo(5, 3);
      f1.show("f1");
      f2 = new Foo(f1);
      f1.a = -99;
      f1.show("f1");
      f2.show("f2");
    }
    
    class Foo {
      int a;
      int b;
    
      Foo(int p0, int p1) {
        a = p0;
        b = p1;
      }
    
      // Copy constructor
      Foo(Foo f) {
        a = f.a;
        b = f.b;
      }
    
      void show(String id) {
        println(id, " = [", a, ",", b, "]");
      }
    }
    

    A copy constructor is one that has a single parameter of the same type as the class.

    Notice that in line 6 we invoke the copy constructor to create a new Foo object.

    The out put from this program shows that we do in fact have 2 independent objects

    f1  = [ 5 , 3 ]
    f1  = [ -99 , 3 ]
    f2  = [ 5 , 3 ]
    

    So this

    // Copy object references
    for (int k=0; k<n; k++)
      objectArray[j][k] = objectArray[j-1][k];
    

    becomes this

    // Copy objects
    for (int k=0; k<n; k++)
      objectArray[j][k]= new Foo(objectArray[j-1][k]);
    

    You obviously have to rename the class Foo to your own.

    HTH but it is a BIG topic area and it would be useful to see your class code to be sure I have provided enough info.

  • similar to quark:

    PVector knows a copy method (method, not constructor) - it returns a type of it's class

    then line 6 in the last sketch would be

    f2 = f1.copy();

    that'd be ok

    the content of the method would return a object

    ;-)

  • edited December 2014

    PVector knows a copy method (method, not constructor) - it returns a type of it's class

    true but the copy method PVector uses a constructor to create a new object.

    public PVector copy() {
      return new PVector(x, y, z);
    }
    

    You could make your own copy method but ultimately all objects have to be created using the new command with a constructor somewhere.

    AFAIK the only exception to using new would be retrieving objects previously serialized and creating them through Java reflection .

  • but that would be a way for him to do it, right? use new in the method copy.

  • edited December 2014

    Well, after perusing my solution once more, realized that if I swap the loop type for right & left shifting cases, no temporary variables are needed at all, like those now & old! #-o
    In short, for right-shifting, do backwards loop. That is, the opposite direction, from tail towards head indices.
    And just invert the situation for left-shifting. A regular loop, from head towards tail indices! o=>

    void rightShift(boolean toShorten) {
      for (int i = vecs.length-1; --i >= 0; vecs[i+1] = vecs[i]);
      if (toShorten & vecs.length > 0)  vecs = (PVector[][]) subset(vecs, 1);
      for (PVector[] row : vecs)  println(row);
    }
    
    void leftShift(boolean toShorten) {
      for (int i = 0, ii = vecs.length; ++i < ii; vecs[i-1] = vecs[i]);
      if (toShorten & vecs.length > 0)  vecs = (PVector[][]) shorten(vecs);
      for (PVector[] row : vecs)  println(row);
    }
    
  • Answer ✓

    but that would be a way for him to do it, right? use new in the method copy.

    Yes that is just as good and in fact gives a clearer solution because all the work is hidden inside the copy method - good idea Chrisir

    I have modified my last example to make use of a copy() method

    Foo f1, f2;
    
    void setup() {
      f1 = new Foo(5, 3);
      f1.show("f1");
      f2 = f1.copy();
      f1.a = -99;
      f1.show("f1");
      f2.show("f2");
    }
    
    class Foo {
      int a;
      int b;
    
      Foo(int p0, int p1) {
        a = p0;
        b = p1;
      }
    
      Foo copy() {
        return new Foo(a, b);
      }
    
      void show(String id) {
        println(id, " = [", a, ",", b, "]");
      }
    }
    
  • Gonna leave the more simplified latest full version below for easier access: O:-)

    /**
     * Array2D Shifting Copy (v2.0)
     * by GoToLoop (2014/Dec/05)
     *
     * forum.processing.org/two/discussion/8477/
     * copying-one-object-array-to-another-including-all-it039s-properties
     */
    
    static final int ROWS = 3, COLS = 2;
    PVector[][] vecs = new PVector[ROWS][COLS];
    
    void setup() {
      println("Array Right-shifting:\n");
    
      for (PVector[] row : vecs) {
        for (int i = 0; i != COLS; row[i++] = PVector.random3D(this));
        println(row);
      }
      println("Length: #", vecs.length, '\n');
    
      rightShift(false);
      println("Length: #", vecs.length, '\n');
    
      rightShift(false);
      println("Length: #", vecs.length);
    
      exit();
    }
    
    void rightShift(boolean toShorten) {
      for (int i = vecs.length-1; --i >= 0; vecs[i+1] = vecs[i]);
      if (toShorten & vecs.length > 0)  vecs = (PVector[][]) subset(vecs, 1);
      for (PVector[] row : vecs)  println(row);
    }
    
    void leftShift(boolean toShorten) {
      for (int i = 0, ii = vecs.length; ++i < ii; vecs[i-1] = vecs[i]);
      if (toShorten & vecs.length > 0)  vecs = (PVector[][]) shorten(vecs);
      for (PVector[] row : vecs)  println(row);
    }
    
  • Thanks so much for the help with this. Using the Copy constructor worked perfectly. A great technique to know about!!

Sign In or Register to comment.