Siyahı generatorları

   Öncəliklə qeyd edək ki, generatorlar ilə siyahı generatorları ayrı-ayrı şeylərdir. Generatorlar funksiyalar mövzusundan sizə tanış gəlməlidir. Belə ki, generatorlar hər iterasiya zamanı müəyyən qiyməti qaytaran funksiyalardır. İndi haqqında bəhs edəcəyimiz siyahı generatorları isə müəyyən qaydalar əsasında qiymətlərlə doldurulmuş siyahılar düzəldən xüsusi sintaksik konstruksiyalardır.

   Siyahı generatorlarının üstünlüyü siyahıları əldə etmək üçün çox qısa koddan istifadə etməsindən ibarətdir. Adi qaydada siyahıların düzəldilməsi nisbətən daha çox kod yazılmasını tələb edir.

Siyahı generatorunun sintaksisi aşağıdakı kimidir:

[ifadə for element in ardıcıllıq/kolleksiya]

   Burada element istifadə olunan dəyişəndir, ardıcıllıq (sətir, siyahı və kortej) və ya kolleksiya (çoxluq və lüğət) elementi götürdüyümüz yerdir, ifadə isə element üzərində aparılan əməliyyatdır.

   Gəlin bir neçə nümunələri nəzərdən keçirək. Aşağıdakı proqram elementləri 1-dən 10-a qədər ədədlərdən ibarət olan siyahı düzəldir:

>>> m = [i for i in range(1, 11)]
>>> print(m)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>>

   Siyahı generatorundan istifadə etmədən də bu məsələni həll etmək olardı. Lakin bu zaman daha çox kod yazmaq lazım gələcəkdi:

>>> m = []
>>> for i in range(1, 11):
	m.append(i)

	
>>> print(m)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>>

   Aşağıdakı proqram elementləri 1-dən 10-a qədər ədədlərin kvadratlarından ibarət olan siyahı düzəldir:

>>> m = [i ** 2 for i in range(1, 11)]
>>> print(m)
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>>

   Siyahı generatoruna şərt də əlavə etmək olar:

>>> num = [1, 4, 3, 17, 8, 9, 22, 6, 13]
>>> m = [i for i in num if i % 2 == 0]
>>> print(m)
[4, 8, 22, 6]
>>>

   Siyahı generatorundakı parametr ifadədə istifadə olunmaya da bilər. Məsələn aşağıdakı nümunədə siyahı 10 təsadüfi ədəddən düzəldilir:

>>> from random import randint
>>> m = [randint(10, 20) for i in range(10)]
>>> print(m)
[20, 11, 16, 14, 16, 17, 18, 11, 11, 12]
>>>

   Siyahı generatorundan istifadə etməklə siyahını klaviaturdan daxil edilən sətirlərlə də düzəltmək olar. Bunun üçün öncə sətirlərin sayını daxil etməlisiniz:

n = int(input())
m = [input() for i in range(n)]

   Siyahı generatorunda kolleksiya kimi lüğət (dict) tipindən də istifadə edə bilərsiniz:

>>> a = {1:10, 2:20, 3:30}
>>> b = [i*a[i] for i in a]
>>> print(b)
[10, 40, 90]
>>>

   Siyahı generatorundan istifadə etməklə iç-içə siyahılar da əldə etmək mümkündür:

>>> m = [[i,i**2,i**3] for i in range(2,10,2)]
>>> print(m)
[[2, 4, 8], [4, 16, 64], [6, 36, 216], [8, 64, 512]]
>>>

   Siyahı generatorunda iç-içə for konstruksiyasından istifadə etmək mümkündür. Bu cür istifadə verilmiş iç-içə siyahıdan bir səviyyəli siyahı əldə etmədə faydalı ola bilər:

>>> a = [[1,10], [2,20], [3,30]]
>>> b = [j for i in a for j in i]
>>> print(b)
[1, 10, 2, 20, 3, 30]
>>>

   Siyahı generatorundan istifadə etməklə fayldan oxunan sətrlərdən də siyahı düzəltmək mümkündür:

f = open("text.txt","r")
lines = [line.strip() for line in f]
f.close()
print(lines)

Generatorlar

   Generatorlar hər iterasiya (təkrarlanan əməliyyat) zamanı müəyyən bir qiyməti qaytaran funksiyalardır. Proqramlaşdırmada generatorlara təmbəl iteratorlar da deyilir. Belə ki, generatorlar yalnız onlardan tələb olunduğu zaman qiymət qaytarırlar. Adi funksiyalardan fərqli olaraq generatorlar qiyməti yield açar sözü ilə qaytarırlar. Generatorlarda funksiyadan çıxış nöqtəsi (daxili dəyişənlərin cari qiymətləri) yadda saxlanılır və növbəti müraciət zamanı funksiyanın işi qaldığı yerdən davam edir.

   Gəlin tələb olunan sayda Fibonaçi ədədlərini əldə etmək üçün generator funksiyadan istifadə edək. Riyaziyyatdan da bildiyiniz kimi ilk iki Fibonaççi ədədləri 0 və 1-dir. Sonra gələn ədəd özündən əvvəlki ilk iki qonşusunun cəminə bərabərdir: 0, 1, 1, 2, 3, 5, 8, 13… Bəzi mənbələrdə sıranın ilk ədədi 0 yox, 1 götürülür.

def fibonacci(n):
    fib1, fib2 = 0, 1
    print('Generasiya başladı...')
    for i in range(n):
        fib1, fib2 = fib2, fib1+fib2
        yield fib1
    print(end='\n')	
    print('Generasiya sona çatdı.')

for fib in fibonacci(10):
    print(fib, end=' ')

    Proqramı incələyək. Əvvəlcə fibonacci() adlı generator təyin edilir. Daha sonra sayğaclı dövrdə dövr ardıcıllığı kimi bu generatordan arqument (10) göndərilərək istifadə edilir. Gördüyünüz kimi dövrdə hər dəfə fibonacci() generator funksiyasına müraciət olunur. Və hər müraciətin nəticəsində generator bir qiymət qaytarır. Generatora ilk müraciətdə əvvəlcə ekrana Generasiya başladı məlumatı çıxarılır. Diqqət yetirin ki, bu sətir yalnız bir dəfə çap olunur. Generatorun daxilində sayğaclı dövr qurularaq Fibonaçi ədədi tapılır və yield açar sözü ilə qiymət olaraq qaytarılır. Burada yield operatorunun istifadəsi generator funksiyanın işində pauza verir və daxili dəyişənlərin (i, fib1, fib2) cari qiymətləri yadda saxlanılır. Bununla da generatorun qaytardığı ilk qiyməti (1) proqramdakı sayğaclı dövrün idarəetmə dəyişəni olan fib qəbul edir və ekranda çapa verilir. Biz burada print() funksiyasında end=’  parametrindən istifadə edirik. Bunu ona görə edirik ki, növbəti Fibonaçi ədədi eyni sətirdə çıxsın. İlk Fibonaçi ədədi ekrana çıxdıqdan sonra dövrdə yenidən fibonacci() generatoruna müraciət olunur və generator öz işinə qaldığı yerdən davam edir. Proses bu minvalla o vaxta qədər davam edir ki, generator daxilindəki sayğaclı dövrün i parametri sonuncu qiymətini (9) almış olsun. Bundan sonra proqramdakı dövrdə yenidən generatora müraciət edildiyi zaman (generator daxilindəki sayğaclı dövr öz işini yekunlaşdırdığına görə) kursor növbəti sətrə keçirilir və ekrana Generasiya sona çatdı məlumatı çıxarılır.

Generasiya başladı...
1 1 2 3 5 8 13 21 34 55 
Generasiya sona çatdı.