Thread overview
Why .dup not work with multidimensional arrays?
May 08, 2015
Dennis Ritchie
May 08, 2015
E.S. Quinn
May 08, 2015
Dennis Ritchie
May 08, 2015
Ali Çehreli
May 08, 2015
Dennis Ritchie
May 08, 2015
Ali Çehreli
May 08, 2015
Dennis Ritchie
May 08, 2015
Chris
May 08, 2015
Hi,
Should the method .dup work with multidimensional arrays for copying?

-----
import std.stdio;

void main() {

	auto a = [1, 2, 3];
	auto b = a.dup;

	b[] *= 2;
	writeln("a = ", a); // [1, 2, 3] // OK
	writeln("b = ", b); // [2, 4, 6] // OK


	auto c = [[[1, 2, 3], [4, 5, 6, 7, 8]],
		  [[9, 10], [11, 12, 13]]];

	auto d = c.dup;

	writeln("d[0][1][1 .. $ - 1] = ",
		 d[0][1][1 .. $ - 1]);

	d[0][1][1 .. $ - 1] *= 3;

	writeln("c = ", c);
	// [[[1, 2, 3], [4, 15, 18, 21, 8]],
	//  [[9, 10], [11, 12, 13]]] // wrong
	writeln("d = ", d);
	// [[[1, 2, 3], [4, 15, 18, 21, 8]],
	//  [[9, 10], [11, 12, 13]]] // OK
}
-----
http://ideone.com/Ddtm47

I thought the slice of the array c[0][1][1 .. $ - 1] = [5, 6, 7] not had to change to [15, 18, 21] by multiplying by 3.
May 08, 2015
It's because arrays are references types, and .dup is a strictly
shallow copy, so you're getting two outer arrays that reference
the same set of inner arrays. You'll have to duplicated each of
the inner arrays yourself if you need to make a deep copy.

On Friday, 8 May 2015 at 02:15:38 UTC, Dennis Ritchie wrote:
> Hi,
> Should the method .dup work with multidimensional arrays for copying?
>
> -----
> import std.stdio;
>
> void main() {
>
> 	auto a = [1, 2, 3];
> 	auto b = a.dup;
>
> 	b[] *= 2;
> 	writeln("a = ", a); // [1, 2, 3] // OK
> 	writeln("b = ", b); // [2, 4, 6] // OK
>
>
> 	auto c = [[[1, 2, 3], [4, 5, 6, 7, 8]],
> 		  [[9, 10], [11, 12, 13]]];
>
> 	auto d = c.dup;
>
> 	writeln("d[0][1][1 .. $ - 1] = ",
> 		 d[0][1][1 .. $ - 1]);
>
> 	d[0][1][1 .. $ - 1] *= 3;
>
> 	writeln("c = ", c);
> 	// [[[1, 2, 3], [4, 15, 18, 21, 8]],
> 	//  [[9, 10], [11, 12, 13]]] // wrong
> 	writeln("d = ", d);
> 	// [[[1, 2, 3], [4, 15, 18, 21, 8]],
> 	//  [[9, 10], [11, 12, 13]]] // OK
> }
> -----
> http://ideone.com/Ddtm47
>
> I thought the slice of the array c[0][1][1 .. $ - 1] = [5, 6, 7] not had to change to [15, 18, 21] by multiplying by 3.
May 08, 2015
On Friday, 8 May 2015 at 02:23:23 UTC, E.S. Quinn wrote:
> It's because arrays are references types, and .dup is a strictly
> shallow copy, so you're getting two outer arrays that reference
> the same set of inner arrays. You'll have to duplicated each of
> the inner arrays yourself if you need to make a deep copy.

Thank you. It really works :)

-----
import std.stdio;

void main() {

	auto c = [[[1, 2, 3], [4, 5, 6, 7, 8]],
		  [[9, 10], [11, 12, 13]]];

	auto d = [[c[0][0].dup, c[0][1].dup],
		  [c[1][0].dup, c[1][1].dup]];

	d[0][1][1 .. $ - 1] *= 3;

	writeln("c = ", c);
	// [[[1, 2, 3], [4, 5, 6, 7, 8]],
	//  [[9, 10], [11, 12, 13]]] // OK
	writeln("d = ", d);
	// [[[1, 2, 3], [4, 15, 18, 21, 8]],
	//  [[9, 10], [11, 12, 13]]] // OK
}
-----
http://ideone.com/kJVUhd

Maybe there is a way to create .globalDup for multidimensional arrays?
May 08, 2015
On 05/07/2015 07:39 PM, Dennis Ritchie wrote:
> On Friday, 8 May 2015 at 02:23:23 UTC, E.S. Quinn wrote:
>> It's because arrays are references types, and .dup is a strictly
>> shallow copy, so you're getting two outer arrays that reference
>> the same set of inner arrays. You'll have to duplicated each of
>> the inner arrays yourself if you need to make a deep copy.
>
> Thank you. It really works :)
>
> -----
> import std.stdio;
>
> void main() {
>
>      auto c = [[[1, 2, 3], [4, 5, 6, 7, 8]],
>            [[9, 10], [11, 12, 13]]];
>
>      auto d = [[c[0][0].dup, c[0][1].dup],
>            [c[1][0].dup, c[1][1].dup]];
>
>      d[0][1][1 .. $ - 1] *= 3;
>
>      writeln("c = ", c);
>      // [[[1, 2, 3], [4, 5, 6, 7, 8]],
>      //  [[9, 10], [11, 12, 13]]] // OK
>      writeln("d = ", d);
>      // [[[1, 2, 3], [4, 15, 18, 21, 8]],
>      //  [[9, 10], [11, 12, 13]]] // OK
> }
> -----
> http://ideone.com/kJVUhd
>
> Maybe there is a way to create .globalDup for multidimensional arrays?

In D, everything is possible and very easy. :p I called it deepDup:

import std.stdio;
import std.traits;
import std.range;
import std.algorithm;

auto deepDup(A)(A arr)
    if (isArray!A)
{
    static if (isArray!(ElementType!A)) {
        return arr.map!(a => a.deepDup).array;

    } else {
        return arr.dup;
    }
}

void main()
{
    auto c = [[[1, 2, 3], [4, 5, 6, 7, 8]],
          [[9, 10], [11, 12, 13]]];

    auto d = c.deepDup;

    d[0][1][1 .. $ - 1] *= 3;

    writeln("c = ", c);
    // [[[1, 2, 3], [4, 5, 6, 7, 8]],
    //  [[9, 10], [11, 12, 13]]] // OK
    writeln("d = ", d);
    // [[[1, 2, 3], [4, 15, 18, 21, 8]],
    //  [[9, 10], [11, 12, 13]]] // OK
}

Ali

May 08, 2015
On Friday, 8 May 2015 at 06:30:46 UTC, Ali Çehreli wrote:
> In D, everything is possible and very easy. :p I called it deepDup:
>
> import std.stdio;
> import std.traits;
> import std.range;
> import std.algorithm;
>
> auto deepDup(A)(A arr)
>     if (isArray!A)
> {
>     static if (isArray!(ElementType!A)) {
>         return arr.map!(a => a.deepDup).array;
>
>     } else {
>         return arr.dup;
>     }
> }
>
> void main()
> {
>     auto c = [[[1, 2, 3], [4, 5, 6, 7, 8]],
>           [[9, 10], [11, 12, 13]]];
>
>     auto d = c.deepDup;
>
>     d[0][1][1 .. $ - 1] *= 3;
>
>     writeln("c = ", c);
>     // [[[1, 2, 3], [4, 5, 6, 7, 8]],
>     //  [[9, 10], [11, 12, 13]]] // OK
>     writeln("d = ", d);
>     // [[[1, 2, 3], [4, 15, 18, 21, 8]],
>     //  [[9, 10], [11, 12, 13]]] // OK
> }
>
> Ali

Thank you. In D it's really easy :)
Recursion, which works with the lambda map looks fine.


I was a little question: why static int idx variable declared within a function deepDup takes the values 1, 1, 1, 2, 2, 3, 4, as opposed to a global variable static int idx, which receives the expected value of 1, 2, 3, 4, 5, 6, 7 ?

-----
import std.stdio,
       std.range,
       std.traits,
       std.algorithm;

// static int idx; // 1, 2, 3, 4, 5, 6, 7 // OK

auto deepDup(A)(A arr)
	if (isArray!A)
{
	static int idx; // 1, 1, 1, 2, 2, 3, 4 // Why is this happening?
	++idx;
	writeln("visited");
	static if (isArray!(ElementType!A)) {
		writeln("ifIdx = ", idx);
		writeln("ifArr = ", arr);
		return arr.map!(a => a.deepDup).array;

	} else {
		writeln("elseIdx = ", idx);
		writeln("elseArr = ", arr);
		return arr.dup;
	}
}

void main() {

	auto a = [[[1, 2, 3], [4, 5, 6, 7, 8]],
		  [[9, 10], [11, 12, 13]]];

	auto b = a.deepDup;

	b[0][1][1 .. $ - 1] *= 3;

	writeln("\nResualt: ");

	writeln("a = ", a);
	// [[[1, 2, 3], [4, 5, 6, 7, 8]],
	//  [[9, 10], [11, 12, 13]]]
	writeln("b = ", b);
	// [[[1, 2, 3], [4, 15, 18, 21, 8]],
	//  [[9, 10], [11, 12, 13]]]
}
-----
http://ideone.com/mAHZyO
May 08, 2015
On Friday, 8 May 2015 at 06:30:46 UTC, Ali Çehreli wrote:
> On 05/07/2015 07:39 PM, Dennis Ritchie wrote:
>> On Friday, 8 May 2015 at 02:23:23 UTC, E.S. Quinn wrote:
>>> It's because arrays are references types, and .dup is a strictly
>>> shallow copy, so you're getting two outer arrays that reference
>>> the same set of inner arrays. You'll have to duplicated each of
>>> the inner arrays yourself if you need to make a deep copy.
>>
>> Thank you. It really works :)
>>
>> -----
>> import std.stdio;
>>
>> void main() {
>>
>>     auto c = [[[1, 2, 3], [4, 5, 6, 7, 8]],
>>           [[9, 10], [11, 12, 13]]];
>>
>>     auto d = [[c[0][0].dup, c[0][1].dup],
>>           [c[1][0].dup, c[1][1].dup]];
>>
>>     d[0][1][1 .. $ - 1] *= 3;
>>
>>     writeln("c = ", c);
>>     // [[[1, 2, 3], [4, 5, 6, 7, 8]],
>>     //  [[9, 10], [11, 12, 13]]] // OK
>>     writeln("d = ", d);
>>     // [[[1, 2, 3], [4, 15, 18, 21, 8]],
>>     //  [[9, 10], [11, 12, 13]]] // OK
>> }
>> -----
>> http://ideone.com/kJVUhd
>>
>> Maybe there is a way to create .globalDup for multidimensional arrays?
>
> In D, everything is possible and very easy. :p I called it deepDup:
>
> import std.stdio;
> import std.traits;
> import std.range;
> import std.algorithm;
>
> auto deepDup(A)(A arr)
>     if (isArray!A)
> {
>     static if (isArray!(ElementType!A)) {
>         return arr.map!(a => a.deepDup).array;
>
>     } else {
>         return arr.dup;
>     }
> }
>
> void main()
> {
>     auto c = [[[1, 2, 3], [4, 5, 6, 7, 8]],
>           [[9, 10], [11, 12, 13]]];
>
>     auto d = c.deepDup;
>
>     d[0][1][1 .. $ - 1] *= 3;
>
>     writeln("c = ", c);
>     // [[[1, 2, 3], [4, 5, 6, 7, 8]],
>     //  [[9, 10], [11, 12, 13]]] // OK
>     writeln("d = ", d);
>     // [[[1, 2, 3], [4, 15, 18, 21, 8]],
>     //  [[9, 10], [11, 12, 13]]] // OK
> }
>
> Ali

Nice one. I have the same problem in one of my modules. I might use the above code henceforth.
May 08, 2015
On 05/08/2015 08:05 AM, Dennis Ritchie wrote:

> why static int idx variable declared within a
> function deepDup takes the values 1, 1, 1, 2, 2, 3, 4, as opposed to a
> global variable static int idx, which receives the expected value of 1,
> 2, 3, 4, 5, 6, 7 ?

That's because every template instance is a different type (or implementation). Just like the static variables of foo and bar are separate below, so are the static variables of t!int and t!float:

void foo()
{
    static int i;
}

void bar()
{
    static int i;
}

void t(T)()
{
    static int i;
}

Ali

May 08, 2015
On Friday, 8 May 2015 at 15:13:14 UTC, Ali Çehreli wrote:
> On 05/08/2015 08:05 AM, Dennis Ritchie wrote:
>
> > why static int idx variable declared within a
> > function deepDup takes the values 1, 1, 1, 2, 2, 3, 4, as
> opposed to a
> > global variable static int idx, which receives the expected
> value of 1,
> > 2, 3, 4, 5, 6, 7 ?
>
> That's because every template instance is a different type (or implementation). Just like the static variables of foo and bar are separate below, so are the static variables of t!int and t!float:
>
> void foo()
> {
>     static int i;
> }
>
> void bar()
> {
>     static int i;
> }
>
> void t(T)()
> {
>     static int i;
> }
>
> Ali

Thankы. Now everything is clear.