Python Programlamaya Giriş 12 - Sıralı Nesnelerle İşlemler

Python Programlamaya Giriş
Author

Kaan Öztürk

Published

January 26, 2018

Daha önceki bir bölümde Python’daki liste, çokuz, dize ve sözlük tiplerinin nasıl kullanıldığını kısaca özetlemiştik. Bu ve bunu izleyen üç yazıda liste, sözlük, dize ve küme veri tiplerine dair daha fazla ayrıntı işleyeceğiz. Dizinin bütün yazılarına erişmek için Python Programlamaya Giriş kategorimize bakabilirsiniz. Bu dizideki yazılar ayrıca Jupyter defterleri halinde GitHub depomuzda da mevcut.

Bu yazının konusu sıralı nesne (sequential object) olarak anılan liste, çokuz ve dize tipleriyle ilgili bazı işlemlerdir. Bunlara sıralı nesne denmesinin sebebi, içlerinde barındırdıkları nesnelerin sırasının önemli oluşu. Söz gelişi, "merhaba" dizesi ile "baharem" dizesi farklıdır, aynı harfleri barındırmalarına rağmen. Buna karşılık bir sözlük sıralı nesne değildir, çünkü {"ahmet":123, "ayşe":456} ile {"ayşe":456, "ahmet":123} aynı sözlüğü tanımlarlar.

Bu yazıda göreceklerimiz: * Dilimleme (slicing) * Öntanımlı fonksiyonlar: range, len, del, list, tuple, join, all, any, enumerate, max, min, sorted, sum, zip * Türkçe alfabeye göre sıralama

Dilimleme

Daha önce, bir L sıralı nesnesinin i indeksli bir elemanına L[i] işlemi ile ulaşabildiğimizi görmüştük. Python’da indeksler sıfırdan başladığı için L[i] listenin i+1’inci elemanını verir.

L = [3,4,5,6,7,8]
L[0] # birinci eleman
3
L[1] # ikinci eleman
4

Bazen sonuncu, sondan ikinci vs. elemanları elde etmek isteriz. Genellikle listenin kaç elemanlı olduğunu tam olarak bilmediğimiz için bunu genel bir ifadeyle yazmamız gerekir. Bunun bir yolu, listenin kaç elemanlı olduğunu veren len fonksiyonunu kullanmaktır.

len(L)
6

Liste indeksleri sıfırdan başlayıp len(L)-1 değerine kadar gider. O zaman sonuncu elemanı L[len(L)-1] ile elde edebiliriz.

L = [3,4,5,6,7,8]
print( L[len(L)-1] ) # sonuncu eleman
print( L[len(L)-2] ) # sondan bir önceki eleman
8
7

Python bu zahmetli yazım yerine doğrudan negatif indeks kullanmaya izin verir. Negatif indeks kullanmak sondan itibaren saymak anlamına gelir. L[-i] ifadesi, sondan i’inci elemanı verir.

print( L[-1] ) # sonuncu eleman
print( L[-2] ) # sondan bir önceki eleman
8
7

Dizinin belli bir alt kümesini almak için L[a:b] ifadesini kullanırız. Bu dilimleme işlemi L[a] elemanından L[b-1] elemanına kadar bir alt dizi verir. Dikkat: Bu alt diziye L[b] dahil değildir.

L[1:4] # ikinci elemandan dördüncü elemana kadar alır.
[4, 5, 6]

Dilimleme işleminde başlangıç indeksini vermezsek, ilk elemandan başlanır.

L[:4]  # birinci elemandan dördüncü elemana kadar alır.
[3, 4, 5, 6]

Bitiş indeksini vermezsek, son elemana kadar gider.

L[4:]  # beşinci elemandan sonuncuya kadar.
[7, 8]

Bitiş indeksi olarak negatif bir sayı verirsek, o negatif sayıyla belirtilen indeksin bir öncesine kadar gider.

L[4:-1] # beşinciden, sondan ikinciye kadar dilim
[7]

Ne başlangıç ne de bitiş indeksi verirsek dizinin aynısı geri verilir. Bu ilk başta faydasız görünse de, listenin bir kopyasını çıkarma amacıyla sık kullanılan bir kalıptır.

L[:]   # baştan sona dilim. Listenin bir kopyasını çıkarmakta kullanılabilir.
[3, 4, 5, 6, 7, 8]

Dilimleme yaparken elemanları atlamamız da mümkündür.

L[1:6:2]  # Birinciden altıncıya kadar iki atlayarak
[4, 6, 8]
L[::2]    # baştan sona kadar iki atlayarak
[3, 5, 7]

Negatif adım vererek diziyi sondan başa tarayabiliriz.

L[::-2]   # sondan başa iki atlayarak
[8, 6, 4]
L[::-1]   # listeyi tersten yaz
[8, 7, 6, 5, 4, 3]

Liste dilimlerine atama yaparak listeyi değiştirmemiz mümkün olur.

L = [3,4,5,6,7,8]
L[1:4] = [-1,-2,-3]   # birinciden dördüncüye kadar elemanları değiştir
L
[3, -1, -2, -3, 7, 8]
L[::2] = [0,0,0]      # baştan sona kadar birer atlayarak elemanları sıfıra ata.
L
[0, -1, 0, -3, 0, 8]

Dize ve çokuzlarla dilimleme

Yukarıda gösterdiğimiz indeksleme ve dilimleme kuralları, sıralı nesne olan dize (string) ve çokuz (tuple) tiplerinde de aynen geçerlidir.

s = "abcçdefgğ"
t = (3,4,5,6,7,8)
s[::-1]
'ğgfedçcba'
t[2:5]
(5, 6, 7)

Tek fark, dize ve çokuzlar değiştirilemez (immutable) veri tipleri oldukları için elemanlarında dilimleme ile değişiklik yapılamaz.

t[2:5] = (-1,-2,-3)
TypeError: 'tuple' object does not support item assignment

Eğer amacımız ortadaki bazı elemanları değiştirilmiş olan bir çokuz elde etmekse, bunu dilimleri birleştirerek sağlayabiliriz.

t = (3,4,5,6,7,8)
t = t[:2] + (-1,-2,-3) + t[5:]
t
(3, 4, -1, -2, -3, 8)

Aynı yöntem tabii dizelerde de geçerli olur.

s = "abcçdefgğ"
s = s[:2] + "XYZ" + s[5:]
s
'abXYZefgğ'

Temel fonksiyonlar

Python’un öntanımlı fonksiyonlarının bir kısmı sıralı nesneler üretmekte veya sıralı nesneler hakkında bilgi edinmekte kullanılırlar. Bunların en yaygınlarının nasıl kullanıldığına bakalım şimdi. Python’daki öntanımlı fonksiyonların tam listesini Python belgelerinde bulabilirsiniz.

range

Tamsayılardan oluşan bir liste üretmek için range(baş, son, adım) işlemini kullanabilirsiniz. Aslında range bir fonksiyon değil, bir veri tipi döndürür. Onu bir listeye çevirmek için ayrıca list işlemi gerekir.

range(10)
range(0, 10)
list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
list(range(2,10))
[2, 3, 4, 5, 6, 7, 8, 9]
list(range(2,10,2))
[2, 4, 6, 8]

range işlemi bir liste değil, dizinin başlangıç, bitiş ve adım bilgilerini barındıran bir nesne geri verir sadece. Bu sayede, range(1000000) gibi çok uzun görünen bir dizi bile bellekte ancak range(10) kadar yer kaplar. Elemanlar ve alt aralıklar gerektiğinde aritmetik olarak hesaplanır.

r = range(0,20,2)
r
range(0, 20, 2)
11 in r
False
10 in r
True
r[:5]
range(0, 10, 2)
r[-1]
18

Bir range nesnesi for döngüsünde doğrudan kullanılabilir.

for i in range(0,20,2):
    print(i,end=" ")
0 2 4 6 8 10 12 14 16 18 

len

Kapsayıcı bir nesnenin kaç nesne barındırdığını verir. Sıralı olmayan tiplerle de kullanılabilir.

len([1,2,3])
3
len("Hello")
5
len({"a": 45, "b": 5.4})
2
len([])
0
len(range(0, 20, 2))
10

del

Genel olarak, belli bir isme bağlı bir nesneyi bellekten kaldırır. Sıralı nesnelerde, bir dilimi silmek için de kullanılabilir.

a = 23
del a
a
NameError: name 'a' is not defined
L = [1,2,3,4,5,6]
del L[1]   # ikinci elemanı siler
L
[1, 3, 4, 5, 6]
del L[2:4]    # üçüncüden dördüncüye kadar olan elemanları siler
L
[1, 3, 6]
del L[:]      # bütün elemanları siler, ama L listesini silmez.
L
[]
del L         # L listesini siler
L
NameError: name 'L' is not defined

list, tuple, join

list fonksiyonu herhangi bir sıralı nesneyi bir liste nesnesine4 çevirmek için kullanılır.

s = "merhaba"
list(s)  # dizeyi listeye çevirir.
['m', 'e', 'r', 'h', 'a', 'b', 'a']
t = (1,2,3,4)
list(t)  # çokuzu listeye çevirir.
[1, 2, 3, 4]

tuple fonksiyonu ise bir sıralı diziyi çokuza çevirir.

s = "merhaba"
tuple(s)
('m', 'e', 'r', 'h', 'a', 'b', 'a')
L = [1,2,3,4]
tuple(L)
(1, 2, 3, 4)

Bir dizenin harflerinden oluşan bir liste veya çokuz oluşturmak kolay olsa da, bunun tersi, yani harf listesini dizeye çevirmek için tek bir komut yok. Bu işlem için kabul edilen kalıp, dizelerin join metodunu kullanmaktır (bir metod, bir nesnenin içinde tanımlanmış bir fonksiyondur).

L = ['m', 'e', 'r', 'h', 'a', 'b', 'a']
"".join(L)
'merhaba'

Genel olarak s.join(L) işlemi L listesinin her elemanını aralarına s dizesini koyarak birleştirir. Yukarıdaki örnekte s bir boş dizeydi, o yüzden L’nin elemanları yanyana yazıldı. Eğer istersek, araya başka karakterler de koyabiliriz.

L = ['m', 'e', 'r', 'h', 'a', 'b', 'a']
"-*-".join(L)
'm-*-e-*-r-*-h-*-a-*-b-*-a'

Dize birleştirmeyi aşağıdaki gibi bir for döngüsüyle de yapabiliriz.

s = ""
for ls in L:
    s = s + ls
s
'merhaba'

all

Bir sıralı nesne içindeki bütün elemanlar mantıksal doğruya denkse True verir, yoksa False verir. Python’da sıfır, boş liste [], boş dize "" gibi yapıların da False sayıldığını; sıfır olmayan sayıların ve boş olmayan nesnelerin de True sayıldığını hatırlayın.

all( [1, 2, 3, 4] )
True
all( (0, 1, 2, 3) )
False
all( "abc" )
True
all( [1, 2, ()] )
False

any

Bir liste içinde en az bir eleman mantıksal doğruya denkse True verir, yoksa False verir. Python’da sıfır, boş liste [], boş dize "" gibi yapıların da False sayıldığını; sıfır olmayan sayıların ve boş olmayan nesnelerin de True sayıldığını hatırlayın.

any( [0, '', True] )
True
any( [0, '', False] )
False
any( [0, 'abc', False] )
True

enumerate

Bir sıralı nesnenin elemanlarına sıra numarası atamak için kullanılır. Özellikle döngülerde, bir nesne üzerinden iterasyon yaparken yararlı olur.

list(enumerate("abcd"))
[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]
for i,c in enumerate("abcçdefgğ"):
    print(i,c)
0 a
1 b
2 c
3 ç
4 d
5 e
6 f
7 g
8 ğ

Bazı problemlerde, bir veri listesini tararken o verinin bulunduğu konuma dair bilgiye de ihtiyaç duyarız. Basit bir örnek olarak, bir isim listesinde Z ile başlayan isimlerin listedeki konumunu görmek isteyebiliriz. Bu amaçla yazdığımız bir for döngüsünde enumerate kullanabiliriz.

isimler = ["Kaan","Meral","Ziya","Fındık"]
for i, isim in enumerate( isimler ):
    if "Z" in isim:
        print(i,isim)
2 Ziya

Python dışındaki dillere alışık olan programcılar bu işlemi bir while döngüsüyle ve bir sayaçla yapmaya çalışırlar, örneğin şöyle bir kodla:

isimler = ["Kaan","Meral","Ziya","Fındık"]
i = 0
while i < len(isimler):
    if "Z" in isimler[i]:
        print(i,isimler[i])
    i += 1
    
2 Ziya

Ancak enumerate ile for kullanmak sadeliği ve okunaklılığı açısından tercih edilir.

max, min

max fonksiyonu bir sıralı nesne veya bir dizi parametre alır, aralarından en büyük değerli olanını geri verir.

max(4,2,8,3,1,7)
8
L = [4,2,8,3,1,7]
max(L)
8

Dizelerden oluşan bir sıralı nesne verildiğinde max alfabetik sırada en ileride olanını döndürür.

max(["dfg","zxy","abc"])
'zxy'
max("merhaba")
'r'

key parametresi ile her elemana önceden uygulanacak bir fonksiyon belirleyebilirsiniz ve maksimum bu fonksiyonun sonucuna göre tespit edilir. Söz gelişi, mutlak değer olarak en büyük elemanı bulmak için key=abs verebilirsiniz.

L = [-1,-3, 4, -5, 2]
max(L, key=abs)
-5

min fonksiyonu verilen bir dizinin içinde, veya parametreler içinde en küçük olanını döndürür. Kullanımı max ile aynıdır.

min(L, key=abs)
-1
min("merhaba")
'a'

sorted

Bir dizi nesnesi alır ve nesne elemanlarının düzgün sıralanmış olduğu bir liste döndürür.

sorted([1, 3, -1, 4, -3, 6, 4])
[-3, -1, 1, 3, 4, 4, 6]

reverse parametresiyle sıralama ters çevrilir.

 sorted([1, 3, -1, 4, -3, 6, 4], reverse=True)      # ters sıralama
[6, 4, 4, 3, 1, -1, -3]

Dizeler alfabetik sıraya konur.

sorted("merhaba")
['a', 'a', 'b', 'e', 'h', 'm', 'r']
sorted(("Ziya","Meral","Kaan","Fındık"))
['Fındık', 'Kaan', 'Meral', 'Ziya']

key parametresine verilen bir fonksiyon sıralamadan önce her elemana uygulanır; sonuç sıralaması bu fonksiyona göre belirlenir.

sorted([1, 3, -2, 4, -5, 6, 4], key=abs)    # mutlak değere göre sıralar
[1, -2, 3, 4, 4, -5, 6]
sorted( [(1,2), (0,2), (3,4), (2,-1)] , key=sum)  # çokuz elemanların toplamına göre sıralar
[(2, -1), (0, 2), (1, 2), (3, 4)]
sorted( [(1,2), (0,2), (3,4), (2,-1)], key=lambda x:x[1]) # ikinci elemana göre sıralar
[(2, -1), (1, 2), (0, 2), (3, 4)]

Türkçe sıralama

Python 3 Unicode kullandığı için İngilizce dışı harfleri kullanırken zorluk çıkarmaz. Ama alfabetik sıralama yapmaya çalıştığımızda doğru cevabı alamayabiliriz.

sorted(("Ahmet","Şebnem","Mehmet","Ziya","İsmail","Ümit"))
['Ahmet', 'Mehmet', 'Ziya', 'Ümit', 'İsmail', 'Şebnem']

Türkçe alfabeye göre sıralama yapmak için yerellik ayarı yapmalıyız. Bunun için locale modülünü yüklemeli, ardından da sorted fonksiyonuna key parametresi olarak locale.strxfrm fonksiyonunu vermeliyiz.

import locale
locale.setlocale(locale.LC_ALL, ("tr", 'UTF-8'))
sorted(("Ahmet","Şebnem","Mehmet","Ziya","İsmail","Ümit"), key=locale.strxfrm)
['Ahmet', 'İsmail', 'Mehmet', 'Şebnem', 'Ümit', 'Ziya']

sum

Bir sıralı nesnenin elemanlarının toplamını verir. Elemanlar sayısal değere sahip olmalıdır.

sum([1,2,3])
6
sum(range(1,101))
5050

zip

Aynı uzunlukta iki veya daha çok listenin aynı konumdaki elemanlarını sırayla alır, bu elemanlardan çokuzlar oluşturur ve bu çokuzların listesini verir.

L1 = [4, 5, 9]
L2 = ['a', 'b', 'c']
list(zip(L1, L2))
[(4, 'a'), (5, 'b'), (9, 'c')]

zip ile farklı verileri birleştirerek bir for döngüsünde işlemek mümkün olur. Tıpkı enumerate gibi zip de bizi elemanları bir sayaç değişkeniyle takip etme mecburiyetinden kurtarır.

yaşlar = [19, 25, 32, 27]
boylar = [170, 180, 175, 169]
ağırlık = [75, 78, 81, 71]
for y, b, a in zip(yaşlar, boylar, ağırlık):
    print("Yaş:", y, "Boy:", b, "Ağırlık:",a)
Yaş: 19 Boy: 170 Ağırlık: 75
Yaş: 25 Boy: 180 Ağırlık: 78
Yaş: 32 Boy: 175 Ağırlık: 81
Yaş: 27 Boy: 169 Ağırlık: 71