Thread overview
Pazar Pazar Çokuzlular (Karşılaştırmalı Bir Örnek)
Jul 18, 2021
Salih Dincer
Jul 19, 2021
Salih Dincer
Jul 19, 2021
Ali Çehreli
Jul 19, 2021
Salih Dincer
July 18, 2021

Merhaba,

Bugün, diğer dillerde de (örneğin Python'da Demetleri) görünce artık D'de Tuple (çokuzlular) kullanma vaktidir dedim kendi kendime. Eşleme tablolarının hızı tamam da karşılığında rasgele dizilmiş veri yapısı bazen işimizi bozabilir...

Bir de Çokuzluları deneyin derim:

import std.array, std.stdio;
import std.range, std.algorithm.sorting : sort;

/* GİRİŞ NOTU:
 * aşağıdaki gibi bir verimiz (aylara göre tavsiye
 * edilen meyveler) ve program başlangıcımız olsun
 */
void main() {
  string[int] mevsimMeyveleri = [
      12:"Portakal", 1:"Nar", 2:"Ayva",
      3:"Muz", 4:"Çilek", 5:"Erik",
      6:"Dut", 7:"Kiraz", 8:"Kayısı",
      9:"İncir", 10:"Mandalina", 11:"Greyfurt"
  ];

 /* EŞLEME TABLOSU:
  * bu veri yapısı hızlıdır fakat sıralı değildir,
  * işte bu yüzden hızlıdır ama yukarıdaki gibi
  * kolayca 4 mevsime bölemeyebiliriz!
  */

Not: Lütfen aşama aşama gidelim ve tüm programı derlemek için bu ara satırları silin. Zaten en sonda çıktısını verdim!

 string[] meyveler; // 0'dan başlayan ay sırası
  for(int ay = 1; ay < 13; ay++)
  {
    meyveler ~= mevsimMeyveleri[ay]; //< diziye
    ay.write(": ", meyveler[$-1]); // ekrana >

    if(ay == 12 )
    {
      writeln;
    } else ", ".write;
  }/* yukarısı ürkütücü değil mi?
    * sıralı almak için bir metot icra etmek
    * zorunda kaldım çünkü foreach() sırasız
    * veriyor ama bir taşla iki kuş vurduk:
    */

  meyveler.writeln("\n"); /* Sırası bozulmadan
  eşleme tablosundan süzülmüş dizge dizisi */

  meyveler = meyveler[$-1] ~ meyveler[0..$-1];
  // artık dilimleme ile sondaki eleman başta


  int[] aylar = [12]; // önce Aralık
        aylar ~= iota(1, 12).staticArray!11;

Not: Lütfen aylar[]'a takılmayın dizi içeriği [ 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ] şeklinde. Kış ayları başta olsun istedim; tıpkı kod içinde yazdığım sıra gibi...

  /* ÇOKUZLUYA GEÇİŞ:
   * Teorik olarak sonradan oluşturulan 2 dizi,
   * bunlar string[] ve int[] birbirlerine bağlı
   * değil. Biz bunu zip() ile birleştiriyoruz:
   */
  auto çokuzlu = zip(aylar, meyveler);

  auto kışMeyveleri = çokuzlu[0..3];
  foreach(meyve; kışMeyveleri)
    meyve[1].write(", ");
  "kış meyveleridir!".writeln;

  çokuzlu.sort!((t1, t2) => t1[0] < t2[0]);
  // Çokuzlu, int[] aylar'a göre sıralandı

  kışMeyveleri.writeln; /* hay aksi :)
  Portakal en sonda çünkü bu bir dilimdi! */

  meyveler.length = 0;
  meyveler.writeln;/* artık index'i 0'dan
  başlayan sıradan diziye ihtiyacımız yok */

  foreach(sırasızMeyveler; mevsimMeyveleri)
    sırasızMeyveler.write(" ");/* artık
  eşleme tablosuna da ihtiyacımız yok çünkü
  sırasız! Benim PC'de Dut, Kiraz Ayva ...*/
  writeln;
  mevsimMeyveleri.clear;
  mevsimMeyveleri.writeln;

  foreach(meyve; çokuzlu) {
    meyve[0].write(": ", meyve[1]);
    if(meyve[0] == 12 )
    {
      writeln;
    } else ", ".write;
  }
} /* ÇIKTISI:

1: Nar, 2: Ayva, 3: Muz, 4: Çilek, 5: Erik, 6: Dut, 7: Kiraz, 8: Kayısı, 9: İncir, 10: Mandalina, 11: Greyfurt, 12: Portakal
["Nar", "Ayva", "Muz", "Çilek", "Erik", "Dut", "Kiraz", "Kayısı", "İncir", "Mandalina", "Greyfurt", "Portakal"]

Portakal, Nar, Ayva, kış meyveleridir!
[Tuple!(int, string)(1, "Nar"), Tuple!(int, string)(2, "Ayva"), Tuple!(int, string)(3, "Muz")]
[]
Dut Kiraz Ayva Greyfurt Portakal Muz Mandalina Nar Kayısı Erik Çilek İncir
[]
1: Nar, 2: Ayva, 3: Muz, 4: Çilek, 5: Erik, 6: Dut, 7: Kiraz, 8: Kayısı, 9: İncir, 10: Mandalina, 11: Greyfurt, 12: Portakal
*/

Bu son bölümde 2 şeye dikkatinizi çekmek istiyorum. Birincisi çokuzluları tıpkı bir dizi gibi dilimleyebiliyoruz. Sanırım bu eşleme tablosunda özellik gereği olmuyor. İkincisi ise çokuzluyu ay sırasına göre tekrar sıraladığımda dilim yine ilk 3 üyeyi gösteriyor ama güncel sırasına göre!

Başarılar...

July 19, 2021
void main() {
  int[] num = [  4,  1,  0,  3, 2];
  string[] str = ["LA", "ni", "Be", "RA", "SI"];
  auto benKopyaDeğilim =
  zip(num, str).sort!(
    (t1, t2) =>
    t1[0] < t2[0]
  );

  foreach(s; str) {
    s.write();
  }
  ": string[] str'nin içeriği".writeln;

  str[0] = "Se";
  foreach(t; benKopyaDeğilim) {
    t[1].write();
  }
  ": benKopyaDeğilim'in içeriği".writeln;
} /* ÇIKTISI:
BeniSIRALA: string[] str'nin içeriği
SeniSIRALA: benKopyaDeğilim'in içeriği
*/

Yukardaki kodla kanıtlanan önemli bir ayrıntı daha var! Çokuzlu, aslında bir dilim gibi referans öğelerini içeriyor olmalı. Çünkü yapılan sıralama işlemi hem çokuzluyu hem diziyi etkiliyor.

Öte taraftan her iki dizi içeriği silinse bile, çokuzlu ilgili bellek bölgesini temsil etmeyi sürdürüyor.

July 19, 2021
Asıl konu bu değil ama bir aralığı başka bir aralıktaki indekslere göre ziyaret etme işlemi Phobos'ta var ama indeks dizisi senin yaptığın gibi "sıra numarası"nı değil, indeksi belirliyor:

import std.stdio;
import std.range;

void main() {
  int[] num = [  2,  1,  4,  3, 0, 2 ];
  string[] str = ["LA", "ni", "Be", "RA", "SI"];
  writefln!"%-(%s%)"(str.indexed(num));
}

Aynı indeks tekrarlanabiliyor. O yüzden çıktıda sonda bir Be daha var:

BeniSIRALABe

On 7/19/21 9:33 AM, Salih Dincer wrote:

> ```d
> void main() {
>    int[] num = [  4,  1,  0,  3, 2];
>    string[] str = ["LA", "ni", "Be", "RA", "SI"];
>    auto benKopyaDeğilim =
>    zip(num, str).sort!(
>      (t1, t2) =>
>      t1[0] < t2[0]
>    );
>
>    foreach(s; str) {
>      s.write();
>    }
>    ": string[] str'nin içeriği".writeln;
>
>    str[0] = "Se";
>    foreach(t; benKopyaDeğilim) {
>      t[1].write();
>    }
>    ": benKopyaDeğilim'in içeriği".writeln;
> } /* ÇIKTISI:
> BeniSIRALA: string[] str'nin içeriği
> SeniSIRALA: benKopyaDeğilim'in içeriği
> */
> ```
> Yukardaki kodla kanıtlanan önemli bir ayrıntı daha var! Çokuzlu, aslında
> bir dilim gibi referans öğelerini içeriyor olmalı.

Doğru ama bu iş çokuzlu yüzünden değil, zip yüzünden de değil. Her ikisi de eleman kopyalıyorlar ama üyelerden 'string' olanı "referans" kavramını taşıyor. Aslında "LA", bellekte şöyle duruyor (örneğin 0x1000 adresinde):

0x1000: L A

Dizinin (ve çokuzlunun ve zip'in elemanlarının) içinde ise şöyle bir eleman var:

struct D_Char_Dizisi {
  size_t length;
  char * ptr;
}

Örneğin, str şöyle:

 [ (1, 0x1000), ... ]

Böyle değerleri (string'leri) sıralayınca (1, 0x1000) yerine örneğin (1, 0x2000) geliyor ve o da 0x2000 adresindeki karakterleri gösteriyor.

> Çünkü yapılan
> sıralama işlemi hem çokuzluyu hem diziyi etkiliyor.
>
> Öte taraftan her iki dizi içeriği silinse bile, çokuzlu ilgili bellek
> bölgesini temsil etmeyi sürdürüyor.

Bu, çöp toplayıcı sayesinde pek şaşırtıcı değil çünkü bellek bölgesini gösteren bir referans olduğu sürece o bellek canlı tutulur.

Ama zip'in sort ile kullanılmasında böyle bir özellik olduğunu bilmiyordum. Bu herhale "zip edilen" bütün aralıklar RandomAccessRange olduğunda mümkündür (aslında,  aşağıda göreceğimiz gibi, RandomAccessRange değil, hasSwappableElements önemli). Örneğin, iota gibi bir aralık kendisi sıralanamaz. Deneyelim:

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

void main() {
  string[] str = ["LA", "ni", "Be", "RA", "SI"];
  auto benKopyaDeğilim =
  zip(5.iota, str).sort!(
    (t1, t2) =>
    t1[0] < t2[0]
  );
}

Derleme hatası kolay anlaşılır gibi değil ama hiç olmazsa "değiş tokuş edilebilen elemanlar" (hasSwappableElements) gerektiğin anlaşılıyor:

  must satisfy one of the following constraints:
       hasSwappableElements!Range
       hasAssignableElements!Range

D'nin bu özelliğini seviyorum: Örneğin zip, elindeki aralıkların çeşidine göre yetenek kazanabiliyor. (İçinde kullanılan 'static if'ler sağolsun.)

Konuyla fazla ilgili olmasa da, şöyle ilginç şeyler de var: chain.sort, ana aralıkların içlerindeki elemanları sanki tek bir aralıkmış gibi sıralar. Benim hiç ihtiyacım olmadı ama bence çok güçlü:

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

void main() {
  auto a = [ 1, 10, 5 ];
  auto b = [ 2, 8 ];
  chain(a, b).sort;

  writeln(a);
  writeln(b);
}

Asıl dizilerin elemanları hep birlikte ele alındıklarında sıralanmış duruma gelirler:

[1, 2, 5]
[8, 10]

Süper çünkü hasSwappableElements olduğu sürece her türlü aralıkla kullanabiliyoruz.

Ali


July 19, 2021
On Monday, 19 July 2021 at 18:36:56 UTC, Ali Çehreli wrote:
>   writefln!"%-(%s%)"(str.indexed(num));
indexed()'i bilmiyordum, şahaneymiş!

Teşekkürler...