VBAMakro |
Koşul ifadeleri ve Döngüler |
3 |
For...Next... Döngüleri
VBA dünyasının en temel döngü tipi For döngüleridir. Bir önceki koşullu
yapılar konusunda söylediğimiz gibi döngüler de programlamanın olmazsa olmazlarıdır.
Onlar olmasaydı belki 3 satırlık kodu onlarca hatta yüzlerce satır şeklinde
yazmamız gerekirdi.
For döngülerinin 2 tipi vardır:
- Basit For Next döngüsü
- For Each döngüleri
İlk olarak basit For döngüsü ile başlayalım
For...Next...
Genel kullanım şekli şöyledir:
For i=başlangıçsayısı to bitişsayısı
'i'ye bağlı veya i'den bağımsız olarak şunu yap
Next i
Gördüğünüz gibi, sayaç olarak kullandığımız i değişkenini döngü
içinde de parametrik olarak kullanabiliriz veya kullanmayabiliriz. İkisine de
örnek verelim. Önce i'yi döngü içinde parametrik olarak kullanacağımız örnek
olsun. Bu örnekte, A1'den A10'a kadar olan hücrelere sırayla i'nin kendisini yazmış oluruz.
For i=1 to 10
Cells(i,1)=i
Next i
Şimdi de parametrik olmayan örneğe bakalım, bunda ise Excele 10 kez bip
sesi çıkarttırıyoruz.
For i=1 to 10
Beep
Next i
i sayacı genelde 0 veya pozitif(ki bu da genelde 1dir) bir sayı olmakla
birlikte negatif bir sayı da olabilir, ama bunun pratikte pek kullanıldığını
görmedim.
Sayacımız normalde 1er 1er artar, ancak istersek
Step ifadesi ise 2'şer, 3'er de arttırabiliriz. Hatta sayacı geriye
doğru da saydırabiliriz, ki bunun için Step ifadesinden sonra negatif bir
sayı gelir.
For i = 10 To 1 Step -2
Cells(i / 2, 1) = i
Next i
Tüm sayfalarda gezindiğimiz bir kod:
For i = 1 To Sheets.Count
Worksheets(i).Select
'diğer kodlar
Next i
Şimdi bir başka örnekte de ilk hücreden en alt hücreye doğru ilerleyelim.
For i = 2 To Cells(1, 1).End(xlDown).Row
Cells(i,1).Select
'Diğer kodlar buraya
Next i
İçiçe For Döngüleri
For döngülerini de tıpkı koşullu yapılarda olduğu gibi iç içe geçmiş
şekilde kullanabiliriz. Aşağıdaki örnekte boş olan hücreleri sarıya
boyayalım ve sayısını bulalım:
Öncelikle şunu belirtmekte fayda var. Tek olsun içiçe olsun tüm döngülerde
For satırını yazdıktan sonra hemen onunu bitişi olan Next satırını da yazın,
aradaki kodları da girintili yazın. İçiçe For Next olacaksa bu ikinci For'u
da yine girintli yazın. Şimdi kodumuza bakalım.
Sub bosluksay()
Dim adet As Integer
For i = 1 To Range("A1").End(xlToRight).Column
For k = 1 To Range("A1").End(xlDown).Row
If IsEmpty(Cells(k, i)) Then
Cells(k, i).Interior.Color = vbYellow
adet = adet + 1
End If
Next k
Next i
MsgBox "toplamda " & adet & " adet boş hücre var"
End Sub
ve sonuç:
For Each...Next...
For Each yapısı bir obje grubu ve bir dizi(veya dizimsi) içindeki elemanlar içinde gezinmek için kullanılır.
For Each nesne in nesnegrubu
'nesneyle ilgili bir işlem
Next nesne
For Each elaman in dizi
'dizi elemanıyla ilgili işlem
Next eleman
Diziler hakkında ön bilgi almak için
buraya tıklayın.
Şimdi yukardaki boşluk saydırma örneğini For Each ile nasıl yapacağımıza
bir bakalım.
Sub bosluksay2()
Dim adet As Integer
Dim hucre As Range, alan As Range
Set alan = Range("A1").CurrentRegion
For Each hucre In alan
If IsEmpty(hucre) Then
hucre.Interior.Color = vbYellow
adet = adet + 1
End If
Next hucre
MsgBox "toplamda " & adet & " adet boş hücre var"
End Sub
Bence For Each ile sanki daha kolay gibi görünüyor. O yüzden böyle bir
görevde ben ForEach'i kullanırdım. Ancak eğer döngü içinde i veya k parametrelerinden
birini kullanarak da bir işlem yapmam gerekseydi, o zaman basit For döngüsü
kullanırdım, gerçi yine For Each kullandığımızda hücrenin row ve column
özellikleri ile i ve k'yı dolaylı olarak elde edebilirim ama basit For'da
bunlar zaten elimde olacaklardı. Kısacası duruma göre hangisini
kullanacağınıza siz karar vereceksiniz. Basit For'un esnek başlangıç ve bitiş
değerleri ile hareket yönündeki esnekliği avantaj sayılabilirlken, For Each
için daha hızlı olmasını avantaj olarak vurgulayabiliriz.
For Each yapısını, Range'teki hücrelere ek olarak, Workbooktaki sayfalar
ve tüm workbooklar arasında dolaşma şeklinde de bol miktarda kullanıyoruz.
'workbooklarda dolaşma
Dim wb As Workbook
For Each wb In Workbooks
MsgBox wb.FullName
Next wb
'worksheetlerde dolaşma
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Sheets
MsgBox ws.Name
Next ws
Yine dizi veya dizimsilerin elemanları içinde gezinirken de her iki yapı
kullanılabilir. Basit For'da 1 to elemansayısı yapısı
kullanılırken ForEach'te each eleman in dizi şeklinde
kullanırız. Şimdi kısa bir örnek de dizilerle ilgili yapalım, daha detaylı
örnekleri Diziler bölümüne bırakalım.
Mesela sabit bir bölge kodu listeniz olsun ve bunların her birini bir
diziye atayalım, sonra da bu bölge kodunu kullanarak bir işlem yapalım.
Sub forarray()
Dim blg() As Variant
blg = Array(5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010)
For Each b In blg
Workbooks.Open ("C:\bölge raporları\" & b & "-netice raporu.xlsx")
'diğer işlemler
Next b
End Sub
Akılda bulundurulması gereken önemli bir husus, ForeEach kullanıldığında read-only bir özellik gösterir. Yani bu yöntemle dizi
elemanlarını değiştiremezsiniz. Elamanları değiştirmek istiyorsanız basit For
döngüsü kullanmanız lazım.
Exlcemacromastery
sitesinden aldığım bu iki örnekte fark çok açıkça anlatılmış.
Sub UseForEach()
' Diziyi yaratıp 3 değer ekliyoruz
Dim arr() As Variant
arr = Array("A", "B", "C")
Dim s As Variant
For Each s In arr
' s'nin atadığı değeri değiştirmeye çalışıyoruz
s = "Z"
Next s
' Ama değişmemiş olduğuğnu görüyoruz
For Each s In arr
Debug.Print s
Next s
End Sub
Basit for ile değişimi görelim
Sub UsingForWithArray()
Dim arr() As Variant
arr = Array("A", "B", "C")
Dim i As Long
For i = LBound(arr) To UBound(arr)
arr(i) = "Z"
Next
For i = LBound(arr) To UBound(arr)
Debug.Print arr(i)
Next
End Sub
Son bir örnek daha yapalım. Bu sefer, toplu bir goalseek(hedef ara) işlemi
yapalım.
Sub toplugoalseek()
Dim h As Range
For Each h In Range("E8:E2294")
h.Select
h.goalseek Goal:=h.Offset(0, 4).Value2, ChangingCell:=h.Offset(0, 2)
Next h
End Sub
Döngüden Çıkış
Yukarıdaki kod örneklerinden de gördüğünüz üzere, For döngüleri
genellikle kaç kez çalıştırılacağını bildiğiniz durumlarda kullanılır.
Ör: For i=1 to 10 dersek, 10 kez çalışacağını biliriz veya
For Each item in
dizi dersek dizideki tüm elemanlar için çalışacağını biliriz. Tabiki üst
limitin değişken olduğu bazı durumlarda, o limite başka VBA kodları ile de
ulaşabilir ve yine For döngülerini kullanabiliriz, mesela en alt satırın kaç
olduğunu bilmiyoruzdur ama Range("A1").End(xlDown).Row ile bunu bilip
döngüyü buraya kadar götürebiliriz, gerçi bu tür durumlarda diğer döngü
türlerini kullanmak daha kullanışlıdır.
Ancak bazen, döngüyü erken terketmeniz gerekebilir. Yani döngüye girdiniz diye
ille sonuna kadar gitmeniz gerekmiyor. Bunun için GoTo ifadesi
kullanılabileceği gibi, Exit For yapısı da kullanılabilir. GoTo kullanımında doğrudan
belli bir etikete yönledirilirken Exit For ile döngünün hemen arkasından devam edilir.
Mesela yukardaki örneğimizi, boşluğa ilk rastlanılan hücrenin
adresini verecek şekilide değiştrelim.
Sub bosluksay3()
Dim a As String
Dim hucre As Range, alan As Range
Set alan = Range("A1").CurrentRegion
For Each hucre In alan
If IsEmpty(hucre) Then
a = hucre.Address
Exit For
End If
Next hucre
If a <> vbNullString Then
MsgBox "ilk olarak " & a & " adresinde boşluğa rastlanmıştır"
Else
MsgBox "herhangi bir boş hücre bulunmamaktadır"
End If
End Sub
TEST SORULARI
Son Sorumuz şuymuş:Bir metindeki tüm noktaları yoketmek istiyorsunuz. Hangi fonksiyonu kullanırdınız?
Soru:
A şıkkı:
B şıkkı:
C şıkkı:
D şıkkı:
Doğru Cevap
Etiketler
İlişkili konuyu seç
204446
Label
* Sorulara verilen yanlış cevaplardaki esprili yorumlarım için hoşgörünüze sığınıyorum.
* Test ve Ödevlerdeki bazı detaylar burada anlatılmamış olabilir. Bunları kendiniz araştırıp bulmalısınız.
* Birden çok konuya ait içeriği olan ödevler var. Algoritmik açıdan bakıldığında o an en uygun konuya adreslenmiştir.
Dikkat! Bir soruya cevap verdikten sonra geri dönemezsiniz.
ÖDEVLER
6
0
Ödev No:11.
Alt indeksi 1, üst indeksi 10 olan 10 elemanlı bir sayı dizisi tanımlayın. Bu dizi 10,20,30,.....100 sayılarını tutacak. bu dizinin veri tipini en uygun tipte belirleyin.
Sonra sırayla tüm dizi elemanlarına yukarıda belirttiğim değerleri atayın. tabiki tek tek değil.
Çözüme bakın(Başka türlü de çözülebilir tabi, bu benim çözümüm.)
Sub Odev_11()
Dim onlar(1 To 10) As Byte
For i = LBound(onlar) To UBound(onlar)
onlar(i) = 10 * i
Next i
MsgBox onlar(2)
End Sub