Thread overview
Çift Boyutlu Dizilerde .dup çalışmıyor
Aug 13, 2021
Salih Dincer
Aug 13, 2021
Ali Çehreli
Aug 13, 2021
Salih Dincer
Aug 13, 2021
Ali Çehreli
Aug 13, 2021
Salih Dincer
Aug 13, 2021
Ali Çehreli
Aug 14, 2021
Salih Dincer
Aug 14, 2021
Ferhat Kurtulmuş
August 13, 2021

Merhaba Ali Hocam,

Bir süredir sıradan dizi imkanlarını kullanarak matrisler üzerinde işlem yapıyorum. Ama .dup istediğim gibi çalışmıyor. En sonunda sadeleştirilmiş örnek hazırlayıp emin oldum. Tek boyutluya çevirdiğinizde (xy'den x'e geçtim) lokaldeki dizi, yapı içinden yapılan değişiklikten etkilenmiyor:

  1   2
  ^-- is copied the contents of the array into it...
100 200
  ^-- content of the array has changed.

Local array: [1, 2]

Acaba nerede hata yapıyorum? Sorunu şu kodda, altındaki çıktısı ile birlikte görebilirsiniz:

import std.format, std.stdio;

struct Bar {
  int[] x;
  int[][] xy;

  this (int[] arr) {
    x = arr.dup;
  }
  this (int[][] arr) {
    xy = arr.dup;
  }
  void toString(void delegate(const(char)[]) str) const {
    str.formattedWrite!"%(%(%3s %)\n%)"(xy);
    str.formattedWrite!"%(%3s %)\n"(x);
  }
}

void main() {
  int[] x = [1, 2];
  int[][] xy = [ [1, 3], [2, 4] ];
  auto foo = Bar(xy);
       foo.writeln("  ^-- is copied the contents of the array into it...");
       foo.xy[0][0] = 100;
       foo.xy[1][0] = 200;
       foo.writeln("  ^-- content of the array has changed.");
       "\nLocal array: ".writeln(xy);
       // But the local has changed too!
}/* ÇIKTISI:
  1   3
  2   4
  ^-- is copied the contents of the array into it...
100   3
200   4
  ^-- content of the array has changed.

Local array: [[100, 3], [200, 4]]
*/

Bu konuda İngilizce forumlarda paylaşılmaya değer bir konu mudur? Yoksa çift boyutlu dizilerde .dup farklı bir şekilde mi kullanmak gerekiyor?

Teşekkürler...

August 13, 2021
On 8/13/21 12:46 AM, Salih Dincer wrote:

> çift boyutlu dizilerde .dup farklı bir şekilde mi kullanmak gerekiyor?

Çift boyutlu dizi diye bir kavram olmadığını hatırlarsak bu sorunu anlamak kolaylaşır. Elemanlarının türü dizi olan dizi tabii ki oluyor ama .dup hep tek dizi üzerinde kullanılır ve o dizinin elemanlarını kopyalar.

Bu durumda bir çözüm, bütün elemanların da ayrı ayrı kopyalanmalarıdır.

Bu konu İngilizce forumlarda da arada bir çıkar. Ne yazık ki "şu nesneyi derinlemesine kopyala" diye bir işlev yok. Ama düşününce çok masraflı olduğu ve hatta derinlerdeki elemanlar için ne karar verileceği de açık olmayabiliyor. Örneğin, üçüncü düzeydeki bir dizinin elemanlarını kopyalamak istemiyoruzdur.

Ben, yazdığım programlarda rahatsızlığını çekmiyorum. Dizi elemanlarının hepsi aynı uzunlukta olduğunda (matris gibi) da zaten bütün elemanlar tek bellekte oturuyorlar ve tek kopyayla hallediliyorlar.

Ali


August 13, 2021
On Friday, 13 August 2021 at 08:25:14 UTC, Ali Çehreli wrote:
> On 8/13/21 12:46 AM, Salih Dincer wrote:
> Bu durumda bir çözüm, bütün elemanların da ayrı ayrı kopyalanmalarıdır.
Anladım, siz bundan bahsediyorsunuz:
```d
  this (int[][] arr) {
    foreach(a; arr) {
      xy ~= a.dup;
    }
  }
```
Vee evet, şimdi çalışıyor :)
August 13, 2021
On 8/13/21 1:35 AM, Salih Dincer wrote:
> On Friday, 13 August 2021 at 08:25:14 UTC, Ali Çehreli wrote:
>> On 8/13/21 12:46 AM, Salih Dincer wrote:
>> Bu durumda bir çözüm, bütün elemanların da ayrı ayrı kopyalanmalarıdır.
> Anladım, siz bundan bahsediyorsunuz:
> ```d
>    this (int[][] arr) {
>      foreach(a; arr) {
>        xy ~= a.dup;
>      }
>    }
> ```
> Vee evet, şimdi çalışıyor :)


Ben de notlarımın arasında şunu buldum:

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!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

August 13, 2021

Hocam bu örnekteki (farklı eleman uzunlukları olan) çok boyutlu dizi kural dışı değil mi?

Bazen yanlış bir kod yazdığım zaman, farklı eleman uzunlukları içeren 2 boyutlu dizi ile karşılıştığım oldu ama bunun bir olanak mı olduğunu hep merak etmişimdir...

Sanırım eski C'den gelen bir tarafım olduğu için çok geleneksel yaklaşıyorum ya da statik dizi ile karıştırıyorum:

#include <stdio.h>
#define x 8
#define y 2

int main() {
  int A44[x][y] =   { 10, 14, 18, 22,
                      11, 15, 19, 23,
                      12, 16, 20, 24,
                      13, 17, 21, 25 };
  int i, j;
  for(i = 0; i < x; i++) {
    for(j = 0; j <y; j++) {
      printf("%3d",A44[i][j]);
    }
    printf("\n");
  }

  return 0;
}

Mesela bu C kodunda 4x4 de planlasam 8x2'ye kolayca çevirdim. Tabi sorumdaki olayı yapamayacağım çünkü bu dinamik bir dizi değil...

August 13, 2021
On 8/13/21 3:31 AM, Salih Dincer wrote:

> Hocam bu örnekteki (farklı eleman uzunlukları olan) çok boyutlu dizi

Yine dedin! :) C, C++, ve D dillerinde çok boyutlu dizi yoktur.

> kural dışı değil mi?

Dinamik dizilerin uzunluğu değişebildiğine göre, dıştaki dizinin elemanlarını serbestçe değiştirebilirim. Derleyicinin araya böyle bir denetimi uygulayacak kodlar eklemesi de çok yavaşlatıcı olurdu. Hatta, nasıl anlayacaksa eleman dizilerin bir biçimde ilişkili olduğunu anlayacak ve birisine eleman eklendiğinde diğerlerine de eklenmiş olduğunu garantileyecek.

Yapabilseydi, çalışma zamanında "bu dizinin boyu 3 oldu ama öteki hâlâ 2" diye atardı. Yani, tek eleman ekleyebilmek için hepsine ekleyen bir düzenek gerekirdi. Hep çok garip olurdu hem de çok kısıtlayıcı olurdu.

Gelen sayıları 7'ye bölümlerinden kalanlarına göre 7 elemanlı bir dizi dizisine eklemek isteyelim:

  const kalan = sayı % 7;
  dizi[kalan] ~= sayı;

Öteki diziler ne olacak? Ne ekleyebiliriz? :)

Aynı uzunluk gereken durumda sabit uzunluklu dizi kullanabiliriz. Veya, bu kavramı şart koşan bir Matris türü yazarız. Veya, veya, veya... :)

>    int A44[x][y] =   { 10, 14, 18, 22,
>                        11, 15, 19, 23,
>                        12, 16, 20, 24,
>                        13, 17, 21, 25 };

> Mesela bu C kodunda 4x4 de planlasam 8x2'ye kolayca çevirdim.

Üstelik sağ tarafta 16 elemanlı tek boyutlu bir dizi var.

> Tabi sorumdaki olayı yapamayacağım çünkü bu dinamik bir dizi değil...

Evet.

Ali


August 14, 2021

On Friday, 13 August 2021 at 20:21:19 UTC, Ali Çehreli wrote:

>

On 8/13/21 3:31 AM, Salih Dincer wrote:

>

Hocam bu örnekteki (farklı eleman uzunlukları olan) çok
boyutlu dizi

Yine dedin! :) C, C++, ve D dillerinde çok boyutlu dizi yoktur.

Yine itiraz :)

Hocam sonuçta bize dizilerde, her çift köşeli parantez için ek bir boyut kavramı düşecek şeklinde öğretildi!

Ancak...

8 saat önce (çünkü uyudum) "Ali hocam neden bahsediyor?" dedim kendi kendime ve hemen Türkçe bir makale okudum:
https://link.medium.com/qOv0MkyUHib (2 Mart 2020)
C Dilinde Çok Boyutlu Diziler (Multi-dimensional Arrays in C) - Necati Ergin

Tabi makale yine alıştığımız bize öğretilen tarzda anlatıyordu ama şu aşağıdaki kısım kafatasımı aydınlatan ışıkları kırpıştırdı :)

>
int b[10][20];
int c[20];

a dizisi her elemanı tek boyutlu dizi olan 10 elemanlı bir dizidir.
b dizisinin boyutu birinci köşeli parantezin içine yazılan 10 değeridir.
b dizisinin elemanları, c dizisi gibi 10 elemana sahip bir dizidir.
b dizisinin elemanlarının türü int [20] türüdür.

Yani temelde tek boyut var ve bellekte bu sıralı veri için 10 x 20 x typeof(b[0][0]).sizeof = 8Kbyte kadar yer ayırıyor. Bizim boyut kavramı da sadece durak noktalarından ibaret, değil mi hocam?

August 14, 2021

On Saturday, 14 August 2021 at 06:13:08 UTC, Salih Dincer wrote:

>

On Friday, 13 August 2021 at 20:21:19 UTC, Ali Çehreli wrote:

>

On 8/13/21 3:31 AM, Salih Dincer wrote:

>

Hocam bu örnekteki (farklı eleman uzunlukları olan) çok
boyutlu dizi

Yine dedin! :) C, C++, ve D dillerinde çok boyutlu dizi yoktur.

Yine itiraz :)

Hocam sonuçta bize dizilerde, her çift köşeli parantez için ek bir boyut kavramı düşecek şeklinde öğretildi!

Ancak...

8 saat önce (çünkü uyudum) "Ali hocam neden bahsediyor?" dedim kendi kendime ve hemen Türkçe bir makale okudum:
https://link.medium.com/qOv0MkyUHib (2 Mart 2020)
C Dilinde Çok Boyutlu Diziler (Multi-dimensional Arrays in C) - Necati Ergin

Tabi makale yine alıştığımız bize öğretilen tarzda anlatıyordu ama şu aşağıdaki kısım kafatasımı aydınlatan ışıkları kırpıştırdı :)

>
int b[10][20];
int c[20];

a dizisi her elemanı tek boyutlu dizi olan 10 elemanlı bir dizidir.
b dizisinin boyutu birinci köşeli parantezin içine yazılan 10 değeridir.
b dizisinin elemanları, c dizisi gibi 10 elemana sahip bir dizidir.
b dizisinin elemanlarının türü int [20] türüdür.

Yani temelde tek boyut var ve bellekte bu sıralı veri için 10 x 20 x typeof(b[0][0]).sizeof = 8Kbyte kadar yer ayırıyor. Bizim boyut kavramı da sadece durak noktalarından ibaret, değil mi hocam?

OpenCv ve numpy gibi kütüphaneler "çok boyutlu" diziler kullanmak yerine aşağıdaki gibi bir yaklaşım izliyorlar. Veri vektörel olunca performans artışı geliyor. Ama Ilya'nın mir kütüphanesinde mat[x][y] gibi erisiliniyor matris elemanlarına. Implemantasyonuna bakmadım hiç, belki de arkasındaki kod vektörizedir (contiguous) ve d'nin sentaks özellikleriyle bu halloluyordur.
    T[] data;

    T opIndex( size_t i, size_t j)
    {
        assert((i < rows) && (j < cols), "index out of bounds!");
        return data[i * cols + j];
    }

    void opIndexAssign(T val, size_t i, size_t j)
    {
        assert((i < rows) && (j < cols), "index out of bounds!");
        data[i * cols + j] = val;
    }