Thread overview
Sequences Processing
April 19

Merhaba,

Aşağıda, anonim işlevler (lambdas, function literals) ve özellikle tek başlarına çok anlam ifade etmediklerinden, eşlemleme (map) ve ergitme (reduce) ifadeleri ile birlikte yer alan sıralı işlem örnekleri var...

La Lambada - lambda, ifade, işlem - eşlem, erime - ergime ?!¡¿ what, onlar da ne 😉

Durun durun, hemen kafanız karışmasın anlatcam :)

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

void main()
{
    auto karesiniAl = (int a) => a * a;
    auto geleniTopla = (int a, int b) => a + b;
    auto aralık = 1.ir(16); /*
    int[] aralık = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];//*/
    [1,2,3,4].map!karesiniAl
             .reduce!geleniTopla
             .writeln; // "30" = 1² + 2² + 3² + 4²

    // aynın şeyleri tekrarlamayalım:
    auto hesapla(R)(R range) {
      return range.map!karesiniAl
             .reduce!geleniTopla;
    }
    hesapla(aralık).writeln; /* "1496" = aşağıdaki
    4 parçanın toplamı (30 + 174 + 446 + 846) */

    auto parçala = aralık.chunks(4);
    parçala.each!(parça => hesapla(parça).writeln);
}
/*
Öncelikle, Ali hocanın yazdığı ir(inclusiveRange) olanağınız yoksa ir yerine iota yazıp son parametereyi 1 arttırın ya da satırın başına // işareti koyarsanız o satır görünmez olur ve altındaki dizi açılır; aralık değildir ama çalışır.*/

Birbirine bağlı örnekler ürkütmesin! Burda, topu topu 2-3 temel konu var ama dilerseniz kendiniz deneyip hem örnek sayısını arttırabilir hem de daha iyi anlayabilirsiniz.

Girişte kullandığım ifadelere gelince. Tabii ki şu an dinlediğim şarkı olan La Lambada ile konumuzun hiçbir alakası yok, sadece isim benzerliği ve espri 😀

Anonim işlevleri (lambda), dilerseniz isim vermeden ve doğrudan map!(...) & reduce!(...) ile tek tek kullanabilirsiniz. Şimdi bir elinizde bir takım işlemler var yani işlevler (lambdas) peki bir işe yarıyor mu?

Yok! (Tıpkı su olmadan tek elinizde sabun ile temizlik yapamamanız gibi...)

Şimdi, diğer elinize eşlemi (map) alıyorsunuz, yani veriyi (örnekteki 1-16 sayı aralığını) ve her parçanın bir kopyasını alıp eşlemleme yapıyorsunuz. Her seferinde, ilgili yordam (lambda) işletilmesinin neticesi "işlem sonucu" üretilir ve bu, sırada göreceğimiz konu olan reduce'daki, gibi başa geri döndürülmeyip bir sonraki veriye geçer. Peki yeter mi?

Yetmez...

Çünkü biz bu sonucu bir döngü içinde, bir sayıyı hafızada teker teker yuvarlayarak da yapabilirdik. Peki farklı her sonucu (sayıyı) topraktaki madenler gibi düşünürsek durum nasıl olurdu?

Yani topraktaki herşeyi (kodlamada sayıları) ısıtıp eriterek (reducing) tıpkı maden filizleri/kristalleri bir araya gelip 30 numaralı madeni (kodlamada ekrana ilk yazdığımız sonuç) elde etmek istiyorsak ne yapıyoruz:

Ergitme (reduce), burada ergiten işlev ona gelen her iki sayıyı topluyor ve lambda görevini yaptıktan sonra reduce(), sonucu başa döndürüp bir sonraki veriyle birlikte işleme devam ediyor. Devamı daha da tatlı!

Farkındaysanız sonra yine benzer bir örneği yapıyoruz. Veriyi chunks() ile parçalara bölüp tekrar olmaması için her birini (4x4) hesapla() işlevinden geçirirsek (burda foreach ile de yapabileceğimiz each'den faydalandık) bu sefer daha faydalı bir örnek yapmış oluruz.

Başarılar...

April 21

On Tuesday, 19 April 2022 at 07:44:39 UTC, Salih Dincer wrote:

>
    //...
    auto parçala = aralık.chunks(4);
    parçala.each!(parça => hesapla(parça).writeln);
}

Son işlediğimiz olanak olan each() ile devam ediyoruz...

Temelde foreach()'den hiçbir farkı yok ama bazı kısıtlamaları var. Örneklerle kısa kısa devam edelim:

import std.array, std.algorithm, std.range;
import std.format, std.stdio;

void main()
{
  int kaçAdet;
  int[string] siD; // string-integer Data
     string[] isD = ["sıfır", "bir", "iki", "üç", "dört",
                     "beş", "altı", "yedi", "sekiz" ];

  //foreach(key, ref value; isD) key.writeln(", ", value);/*
  isD.each!( (key, ref value) {
    writefln!"%s, %s"(key, value);
    kaçAdet++;
  });//*/
  kaçAdet.writeln;

  /* Dilerseniz, alıştığımız foreach() başındaki // işaretini
   * kaldırın ve benzer sonucu alabildiğinize şahit olun!
   */

Kısaca, üzerinde gezindiği aralık veya dizinin hangi elemanını aktardığını (key), o sırada üzerinde durduğu veriyi (value) aktarır. Bunu yaparken de sanki bir lambda function izlenimi verir. Yani tek satır yapabildiğimiz gibi birden fazla satır şeklinde kodumuzu each() içine gömebiliyoruz...

  //... KODUN DEVAMI, aşağıdaki Associative Array ve kaynağı iSD
  siD = [ isD[0]: 0, isD[1]: 1, isD[2]: 2, isD[3]: 3, isD[4]: 4,
          isD[5]: 5, isD[6]: 6, isD[7]: 7, isD[8]: 8 ];

  auto app = appender!string();
  alias f = void delegate (string key, int value);

  f result = (string key, int value) {
       app.formattedWrite("%s: %s\n", key, value);
  };

  //siD.each!( (key, value) => result(key, value) );/*
  siD.each!( (key, ref value) => writef("%s: %s\n", key, value) );//*/
  app.data.writeln;

}

Eğer sizin için tek satır yeterliyse, daha önce yaptığımız gibi hemen lambda işareti (=>) ile kodlamanıza devam edebilirsiniz. Ancak burada bir işlev veya write() kullanabiliyorsunuz. Örneğin doğrudan formattedWrite() nedense çalışmıyor. O yüzden Appender kullanmak zorunda kaldım ya :)

Fazladan delegate() ise biraz renk katmak için. Yani artistlik olsun diye :) Yoksa sıradan bir işlev de işinizi görür.

Örneklerin çıktıları sırasıyla şöyle:

>

0, sıfır
1, bir
2, iki
3, üç
4, dört
5, beş
6, altı
7, yedi
8, sekiz
9

>

altı: 6
dört: 4
üç: 3
iki: 2
bir: 1
sıfır: 0
beş: 5
sekiz: 8
yedi: 7

Sevgiler, saygılar...

April 25

On Tuesday, 19 April 2022 at 07:44:39 UTC, Salih Dincer wrote:

>

eşlemleme (map)

map()'den hemen kurtulamayacağız! Çünkü bugün güzel ve pratik bir özellik öğrendim...:)

Pseudeo kodu kısaca şu:

struct Foo ( string str )
// string kapsülleyen bir struct var ve

str[ "beş", "bir", "iki" ]
// dizge dizisini (string[]) alıp

result = str.map!Foo.array
// Foo[] dizisi olarak eşlemleyebilirsiniz...

Basit ve çok çok güzel değil mi? Ama kazın ayağı hiç öyle değil! Çünkü chunks() ve take() gibi başka olanaklar ile kullanılamıyor. Ayrıca toString() ile özelleştirilemiyor. Sanırım, this() kurucu üye eklenince bile, map() patlıyor! Onun patlamaması için basitlikten uzaklaşmak gerek:

import std.algorithm, std.stdio;

void main() {
  struct Foo {
    string s; /*
    string s;
    string toString() {
      return s;
    }//*/
  }
  auto arr1 = ["abc", "def", "ghi"]
              .map!Foo.array; /*
              .map!(a => Foo(a))
              .array;//*/

  typeof(arr1).stringof.writeln(": ", arr1);

  struct Bar {
    string s;
    //*
    this(R)(R result) {
      import std.conv : to;
      this.s = result.to!string;
    }//*/

    string toString() {
      return s;
    }
  }
  auto arr2 = "abcdefghi"
             .chunks(3)
             .map!(a => Bar(a))
             .array;

  typeof(arr2).stringof.writeln(": ", arr2);

} /* ÇIKTISI:
Foo[]: [Foo("abc"), Foo("def"), Foo("ghi")]
Bar[]: [abc, def, ghi]
*/

Alternatif örneklerle (toggle'ları aç/kapa yaparak) görüleceği üzere map() patlıyor ve tabi yukardaki haliyle çalışıyor.

Ama başlangıçta Foo, Bar'daki gibi bir sonuç/aralık döndüren (örnekteki chunks gibi) bir şeyle kullanamıyorsunuz. Basitlik için güzel yine de lamba ile şu şekilde açıkça belirtmediğiniz sürece genişletilemiyor:

.map!(a => Foo(a)).

Kolay gelsin... 😀

April 25
On 4/25/22 16:50, Salih Dincer wrote:

> ```chunks()``` ve ```take()``` gibi başka olanaklar ile kullanılamıyor.

Kullanılabilmesi gerek. Bir örneğini gösterir misin?

>    auto arr1 = ["abc", "def", "ghi"]
>                .map!Foo.array; /*
>                .map!(a => Foo(a))
>                .array;//*/

> Alternatif örneklerle (toggle'ları aç/kapa yaparak)

Ben onu hiç öğrenemeyeceğim ama deneyeyim şimdi. :(

> görüleceği üzere
> ```map()``` patlıyor ve tabi yukardaki haliyle çalışıyor.

Benim gibi basit insanlar için en iyisi, hiç toggle koymadan çalışmayan kodu göstermek. O zaman anlıyorum.

Denedim ama neyin çalışmadığını anlamadım. Hepsi derlendi ve hepsi bir çıktı üretti. Beklediğin gibi çalışmayan map örneğini beklemek en iyisi...

Ali

April 26

On Tuesday, 26 April 2022 at 00:46:35 UTC, Ali Çehreli wrote:

>

Denedim ama neyin çalışmadığını anlamadım. Hepsi derlendi ve hepsi bir çıktı üretti. Beklediğin gibi çalışmayan map örneğini beklemek en iyisi...

Pardon hocam,

Pseudeo kodda ifade ettiğimi vurgulamak istemedim. Yani çalışmayan ve esnek olmayan o kazın ayağını göstermeyim dedim 😀

Aslında o kod da çalışıyor ama yapı içinde dizge türündeki s dışında bir şey olmayacak. Bir nevi string başka bir yapı ile kapsülleniyor. İşte o zaman string[].map!Bar.array çalışıyor. Ama işin içine chunks katarsanız map patlıyor; en azından beniö eski sürümde. Yabancı forumda paylaştığım şu örnekleri yeni sürümde denemedim:

https://forum.dlang.org/post/pclfaqwfbcrwthjhcygc@forum.dlang.org

Başarılar...

May 14

On Tuesday, 19 April 2022 at 07:44:39 UTC, Salih Dincer wrote:

>

[...] lambda görevini yaptıktan sonra reduce(), sonucu başa döndürüp bir sonraki veriyle birlikte işleme devam ediyor.

Yakın zamana kadar, aralıklar döndüren yapıların unittest'lerinde önce .array ile sonucu diziye çevirip sonra bunu şöyle dilimliyordum:

assert(falancaAralığınDizisi[$-2..$] == [54, 55]);

Şimdi yeni bir şey öğrendim; hem de forumun Captcha algoritması bunu bana sorarak öğretti! Meğer reduce!max diye bir şey varmış:

  enum testValue = 55;
  assert(inclusiveRange(testValue).reduce!max == testValue);
  testValue.writeln;

Test ettiğiniz aralık çok uzunsa, sondaki değerlerin veya son elemanın (yukardaki max buna işaret ediyor) doğru olmasını istersiniz. Son geliştirdiğimiz InclusveRange yapısına opSlice() yüklemeleri bu işi kolaylaştırıyordu. Ama bu özellikler yoksa reduce!max pekala imdadınıza koşabilir.

Buna doğrudan çözüm denir!

Dolaylısında ise, retro() ile aralığı ters çevirip take() ile baştan eleman çekiyordum. İşte bunu sağ kolunuzu boynunuzdan çevirip sol kulağınızı tutmaya benziyor. Gün geçmiyor ki insan bir şey öğrenmesin...