Jump to page: 1 2
Thread overview
DenkTekrarlayan!Aralık Ali'den, çok güzel!
Sep 01, 2022
Salih Dincer
Sep 01, 2022
Ali Çehreli
Sep 01, 2022
Salih Dincer
Sep 01, 2022
Salih Dincer
Sep 01, 2022
Ali Çehreli
Sep 02, 2022
Salih Dincer
Sep 02, 2022
Ali Çehreli
Sep 02, 2022
Ali Çehreli
Sep 02, 2022
Salih Dincer
Sep 02, 2022
Ali Çehreli
Sep 02, 2022
Salih Dincer
Sep 02, 2022
Ali Çehreli
September 01, 2022

Merhaba,

Son günlerdeki okuma maratonunu biraz genişlettim; geçmişe, taa 2010'a kadar götürdüm. Ali hocanın o zamanlar yaptığı çok güzel bir kod var. Eski başlığı hortlatmak yerine, biraz günümüze uyarlayarak (kodun orijinaline* sadık kalarak) burada ön plana çıkarmak istedim...

Aslında yaptığı basit gibi görünse de aralıkların kullanılarak yapılması kodu çok kıymetli hale getiriyor. Hatta başlangıçta yoğunluğu arttırılan ardışık sayıların frekansını düşürmek mümkün:

import std.format, std.string, std.stdio;
import std.algorithm, std.range;
/**
 * Kendisine verilen aralıktaki elemanların
 * belirtilen sayıda art arda tekrarlandığı
 * bir giriş aralığı (InputRange) döndürür.
 **/
struct DenkTekrarlayan(Aralık)
       if(isInputRange!Aralık)
{
  Aralık asılAralık;
  int tekrarSayısı;
  private int sayaç;

  ElementType!Aralık şimdikiEleman;

  this(Aralık asılAralık, int tekrarSayısı) {
    this.asılAralık = asılAralık;
    this.tekrarSayısı = tekrarSayısı;

    if(!asılAralık.empty) {
      şimdikiEleman = this.asılAralık.front;
    }
  }

  bool empty()  {
    return asılAralık.empty;
  }

  ElementType!Aralık front()  {
    return şimdikiEleman;
  }

  void popFront() {
    if(++sayaç == tekrarSayısı) {
/**
  * Tekrarlarımızı tamamladık; asıl aralıktaki
  * bir sonraki elemana geçmemiz gerekiyor...
 **/

    while(!asılAralık.empty &&
          (asılAralık.front == şimdikiEleman))
    {
      asılAralık.popFront();
    }

    if(!asılAralık.empty) {
      şimdikiEleman = asılAralık.front;
    }
    sayaç = 0;
    }
  }
}

auto denkTekrarlı(R)(R e, int t) if (isInputRange!R)
{
   return DenkTekrarlayan!R(e, t);
}

struct SonsuzSayaç(type)
{
   type sayaç;
   enum empty = false;
   type front() const { return sayaç; }
   void popFront() { ++sayaç;}
}

void main()
{
  auto elemanlar = [ 0, 1, 1, 1, 2, 0 ];
  write("(1) - Elemanları ikişer kere tekrarla:\n\t");
  writeln(elemanlar.denkTekrarlı(2));

  write("(2) - ve baştaki üç tanesini seç:\n\t");
  writeln(elemanlar.denkTekrarlı(2).take(3));

  writeln;

  "(3) * ilk iki çifti seç, ve beşer kere tekrarla\n\t".
  write(
    [ 2, 4, 6 ].take(2).denkTekrarlı(5)
 );

  writeln; writeln(`
  Sonsuza kadar artan değerler üret,
  her birisini dörder kere tekrarla,
  ve baştaki yirmi tanesini seç:`);

  SonsuzSayaç!uint sonsuzSayaç;
  auto sonTest = sonsuzSayaç.denkTekrarlı(4).take(20);

  writefln("%-(%s %)", sonTest);/* Orijinal örnek:
  writeln(take(denkTekrarlı(sonsuzSayaç, 4), 10));//*/

  auto testlerBitmez = sonTest.denkTekrarlı(2);
  testlerBitmez.writeln; // :)
}
/* ÇIKTISI:

(1) - Elemanları ikişer kere tekrarla:
	[0, 0, 1, 1, 2, 2, 0, 0]
(2) - ve baştaki üç tanesini seç:
	[0, 0, 1]

(3) * ilk iki çifti seç, ve beşer kere tekrarla
	[2, 2, 2, 2, 2, 4, 4, 4, 4, 4]

  Sonsuza kadar artan değerler üret,
  her birisini dörder kere tekrarla,
  ve baştaki yirmi tanesini seç:
0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4
[0, 0, 1, 1, 2, 2, 3, 3, 4, 4]
*/

(*) Emin değilim (biraz zaman geçti) ama sanırım bazı kolaylık işlevlerini iptal ettim ve UFCS nimetlerini olabildiğince göstermek istedim. Özetle kodun orijnalinden azıcık uzaklaşmış olabilirim.

>

Çıktısı:

'"Elemanları ikişer kere tekrarla"
[0, 0, 1, 1, 2, 2, 0, 0]
"Elemanları ikişer kere tekrarla, ve baştaki üç tanesini seç"
[0, 0, 1]
"Baştaki dört tanesini seç, ve beşer kere tekrarla"
[3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1]
"Sonsuza kadar artan değerler üret, her birisini dörder kere tekrarla, ve baştaki on tanesini seç"
[0, 0, 0, 0, 1, 1, 1, 1, 2, 2]
'

Devamı gelecek... :p

Ali

Sanırım devamını ben getirmiş oldum. Ali hocada bir kahinlik seziyorum. Nereden bildi acaba devamının geleceğini :)

Şaka bir yana (1) ve (2)'nci örneklerin sonucu orijinali ile aynı. Sonrasında biraz doğaçlamaya gitmek istemişim. Ayrınca sınıfı yapıya çevirip bazı const'ları iptal ettim. Çünkü testlerBitmez örneğinde hata verdi. İsterseniz üzerinde biraz yazışalım?

Sevgiler, saygılar...

September 01, 2022
On 9/1/22 11:12, Salih Dincer wrote:

> /**
>   * Kendisine verilen aralıktaki elemanların
>   * belirtilen sayıda art arda tekrarlandığı
>   * bir giriş aralığı (InputRange) döndürür.
>   **/

Şöyle de oluyor mu? :)

import std;

auto denkTekrarlı(R)(R r, int t) if (isInputRange!R) {
  return r.map!(e => repeat(e, t)).joiner;
}

void main() {
  auto elemanlar = [ 0, 1, 2, 0 ];
  write("(1) - Elemanları ikişer kere tekrarla:\n\t");
  writeln(elemanlar.denkTekrarlı(2));
}

Ali
September 01, 2022

On Thursday, 1 September 2022 at 18:35:52 UTC, Ali Çehreli wrote:

>

Şöyle de oluyor mu? :)

  return r.map!(e => repeat(e, t)).joiner;

Olmuyor hocam çünkü sizin kod denk tekrarlıyor; yani tüm veriyi tekrarlamıyor. Önce fazladan tekrarların frekansını düşürüyor sonra gelen parametreye göre tekrarlıyor. Öte taraftan son bir örnekte bu daha belirgin (normalde 2 "ali" olmalı!):

  ["ali", "ali", "ala", "oya", "aya","oya"].denkTekrarlı(2).take(10).writeln;
  // ["ali", "ali", "ala", "ala", "oya", "oya", "aya", "aya", "oya", "oya"]

S.Dinçer

September 01, 2022

On Thursday, 1 September 2022 at 18:55:32 UTC, Salih Dincer wrote:

>

On Thursday, 1 September 2022 at 18:35:52 UTC, Ali Çehreli wrote:

>

Şöyle de oluyor mu? :)

  return r.map!(e => repeat(e, t)).joiner;

Olmuyor hocam [...]

Belki de oluyordur ama dizin sonundaki 2. "oya" grubunu slide()'a dahil edemedim :(

void main()
{
  auto arr = ["ali", "ali", "ala", "oya", "aya","oya", "oya"];
       arr.slide(2)
          .filter!(a => a[0] != a[1])
          .map!(e => e[0].repeat(2))
          .joiner.writeln;

  arr.denkTekrarlı(2).writeln;
}
/* ÇIKTISI:
["ali", "ali", "ala", "ala", "oya", "oya", "aya", "aya"]
["ali", "ali", "ala", "ala", "oya", "oya", "aya", "aya", "oya", "oya"]
*/

Belki daha da basit yolu vardır?

Kolay gelsin...

September 01, 2022
On 9/1/22 13:47, Salih Dincer wrote:

>            .filter!(a => a[0] != a[1])

O da uniq() olarak var. :)

import std;

auto denkTekrarlı(R)(R r, int t) if (isInputRange!R) {
  return r.uniq.map!(e => repeat(e, t)).joiner;
}

void main() {
  auto elemanlar = [ 0, 1, 1, 1, 2, 0 ];
  write("(1) - Elemanları ikişer kere tekrarla:\n\t");
  writeln(elemanlar.denkTekrarlı(2));
}

Çıktısı:

(1) - Elemanları ikişer kere tekrarla:
	[0, 0, 1, 1, 2, 2, 0, 0]

Ali

September 02, 2022

On Thursday, 1 September 2022 at 22:47:41 UTC, Ali Çehreli wrote:

>

On 9/1/22 13:47, Salih Dincer wrote:

>
       .filter!(a => a[0] != a[1])

O da uniq() olarak var. :)

Çok basitmiş :)

Aklıma gelmişken yazayım, cached() özelliği üzerine çalışıyordun; ne oldu hocam?

Bildiğim kadarıyla zaten cache() diye bir şey varmış ama yukarda yaptığımız tarzda programlama yaparken cached() ile daha verimli kodlar çıkaracağız. Ne zaman Phobos'a entegre edilir?

Bir soru daha:

Şu örnekte uniform!"[]" şekilde derleyemedim, acaba neden? Ben de fazladan enum elamanı ekledim!

import std;
void main()
{
  enum testAdeti = 300;
  auto tekrarsız = rasgeleDNA(testAdeti).uniq;
  auto dizi = tekrarsız.array;
  assert(dizi.length < testAdeti);
  dizi.length.writeln(": ", tekrarsız);
  dizi.map!(e => repeat(e, 2))
      .joiner
      .writefln!"%(%s%)";
}


auto rasgeleDNA(size_t adet) {
  enum DNA { T, C, G, A, N }
  return generate!(() =>
           uniform(DNA.T, DNA.N))
           .takeExactly(adet);
}

Teşekkürler...

September 01, 2022
On 9/1/22 22:00, Salih Dincer wrote:

> cached() özelliği üzerine çalışıyordun; ne oldu hocam?

druntime'ın dilimler için bellek ayırma yöntemine bağlı bir sorunla karşılaştım. O yüzden kendim önce bir "expanding circular buffer" yazmaya karar verdim.

> zaten cache() diye bir şey varmış

Yalnızca .front elemanın kopyasını alır. Ben belirsiz sayıda elemanı saklamak istiyorum.

> Ne zaman Phobos'a entegre edilir?

Phobos'a benzer biçimde yazmaya çalışıyorum ama hiç öyle bir garanti yok. Ama karşılaştığım bir kaç ilginç konu, DConf Online sunumu olabilir. :)

> Şu örnekte uniform!"[]" şekilde derleyemedim, acaba neden?

uniform, ilk değeri ve ilk değerin bir fazlasını alır. N olmazsa A dışarıda kalırdı:

>    enum DNA { T, C, G, A, N }

Bu durumda uniform'a "[]" verilebilir:

  enum DNA { T, C = 10, G, A }
  foreach (_; 0 .. 10) {
    writeln(uniform!"[]"(DNA.min, DNA.max));
  }

Ve nasıl yapıyorsa çok da akıllı çünkü değerler birer birer artmadığında bile doğru çalışıyor. (Yukarıda C'yi arada 10 yapıyorum.)

Ali

September 02, 2022
On 9/1/22 23:48, Ali Çehreli wrote:

>      writeln(uniform!"[]"(DNA.min, DNA.max));

Şu da aynı anlama geliyormuş:

  uniform!DNA

Ali

September 02, 2022

On Friday, 2 September 2022 at 06:48:09 UTC, Ali Çehreli wrote:

>

On 9/1/22 22:00, Salih Dincer wrote:

Bu durumda uniform'a "[]" verilebilir:

  enum DNA { T, C = 10, G, A }
  foreach (_; 0 .. 10) {
    writeln(uniform!"[]"(DNA.min, DNA.max));
  }

Nedense DNA.min ve DNA.max ile denememe rağmen çalışmıyor hocam. Hatta playground'da da denedim; orada online, son sürüm ve şu hatayı aldım:

>

/dlang/dmd/linux/bin64/../../src/phobos/std/range/package.d(3808): Error: cannot modify immutable expression this.elem_
/dlang/dmd/linux/bin64/../../src/phobos/std/range/package.d(3767): Error: template instance std.range.primitives.isInputRange!(Generator!(function () @safe => uniform(DNA.T, DNA.N))) error instantiating
/dlang/dmd/linux/bin64/../../src/phobos/std/range/package.d(3767): while evaluating: static assert(isInputRange!(Generator!(function () @safe => uniform(DNA.T, DNA.N))))
/dlang/dmd/linux/bin64/../../src/phobos/std/range/package.d(3723): Error: template instance std.range.Generator!(function () @safe => uniform(DNA.T, DNA.N)) error instantiating
onlineapp.d(18): instantiated from here: generate!(function () @safe => uniform(DNA.T, DNA.N))

Muhtemelen sorun, generates() ile olan bir uyumsuzluktan kaynaklanıyor. Veee (!) evet, çok güzel tespit. Adeta enum'un elemanları üzerinde yürüyor! Şaşırdım ama bu mekanizma sola ve sağa kapalı yani "[]" olduğunda çalışıyor. Örneğin:

import std;
void main() {
  enum DNA { t = 84,
             c = 67,
             g = 71,
             a = 65 }
  char[] gene;
  enum adet = 30;
  foreach (_; 0..adet) {
    gene ~= uniform!"[]"(DNA.min, DNA.max);
  }
  gene.writeln;

  auto range = generate!(() =>
               uniform(DNA.min, DNA.max))
               .takeExactly(adet);
  range.writeln;
} /* ÇIKTISI:
ATAGTCCAACTGCTGGTTGGCCAGGATCGA
[cast(DNA)76, a, cast(DNA)76, cast(DNA)76, cast(DNA)82, cast(DNA)83, cast(DNA)69, cast(DNA)75, cast(DNA)79, cast(DNA)75, c, cast(DNA)70, a, cast(DNA)80, cast(DNA)66, cast(DNA)76, cast(DNA)81, cast(DNA)74, cast(DNA)75, cast(DNA)83, cast(DNA)80, cast(DNA)77, cast(DNA)72, cast(DNA)83, a, g, cast(DNA)79, cast(DNA)79, cast(DNA)73, cast(DNA)79]
*/

Yine de bu tespit benim sorunumu çözmüyor. Çünkü uniform() dışarda harika çalışıyor ama generates!(() => ...) içine lambda ile girince (ya da literal function mu desek?) işler yolunda gitmiyor...

S.Dinçer

September 02, 2022
On 9/2/22 00:44, Salih Dincer wrote:

> Muhtemelen sorun, generates() ile olan bir uyumsuzluktan kaynaklanıyor.

Evet, bir Phobos hatası: Generator'ın elem_ üyesi için Unqual kullanılması unutulmuş:

  https://issues.dlang.org/show_bug.cgi?id=23319

Ali

« First   ‹ Prev
1 2