46 Łagodne wprowadzenie do R
> # to pętla wykona się dla każdego elementu wektora 'indeksy' ale zmienna
'i' nie będzie przyjmowała za wartości elementów tego wektora ale jego indeksy. Innymi słowy w pierwszym wywołaniu wartością ‘i’ nie będzie wartość ‘jabłka’ ale wartość ’1‘
> for (i in seq_along(indeksy)) {
+ cat(pastę(indeksy[i] , ’'\n"))
j ablka gruszki truskawki pomarańcze
Zazwyczaj podobny efekt do pętli for możemy uzyskać stosując funkcje z rodzi- | ny *apply() (np. lapplyO). Funkcje te będą przedstawione w podrozdziale 2.1.3. J Żadne z tych rozwiązań nie jest absolutnie lepsze, można więc korzystać z dowolne- ż go z nich w zależności od tego, które jest łatwiej w konkretnej sytuacji zastosować : | (zapisać). Najczęściej jednak używając funkcji z rodziny *apply() otrzymuje się j bardziej elegancki zapis, w wielu przypadkach też wynik wyznaczony będzie szybciej | ponieważ R jest optymalizowany do pracy na wektorach.
1.6.1.5 Pętla while
Pętla for ma z góry określoną liczbę powtórzeń do wykonania (wyznaczoną przez długość wektora wekt). W pewnych sytuacjach nie wiemy ile powtórzeń pętli będzie wymaganych, aby uzyskać zamierzony efekt. W takich sytuacjach wygodniej jest wykorzystać pętlę while. Poniżej przedstawiamy jej składnię.
while (war) instr
Instrukcja instr będzie wykonywana tak długo, dopóki war unek war jest prawdziwy. Oczywiście, należy zadbać o to, by taka sytuacja kiedykolwiek zaistniała, a więc by pętla się zakończyła. Poniżej przykład z wykorzystaniem pętli while.
> i-0
’i<3‘ będzie prawdziwy
> # pętla będzie się wykonywać póki warunek
> while(i < 3) {
+ cat(p<i8te("juz",i,"\n"))
+ i - i+1 ♦ > juz 0
juz 1 '
juz 2 1.6.1.6 Pętla repeat
W języku R istnieje też trzeci rodzaj pętli. Przyznam, że niechętnie o nim piszę i raczej bym go nie polecał. Tą czarną owcą jest pętla repeat, której składnia przedstawiona jest poniżej.
Przyśpieszamy
47
. ż*epeat lustr
Moim zdaniem, korzystanie z tego sposobu kończenia pętli jest w bardzo złym stylu.
Działanie tej pętli polega na powtarzaniu instrukcji lnatr tnk długo aż .... Właśnie, nie ma tu żadnego warunku stop! Działanie znal mile przerwane wyłącznie w wyniku wygenerowania błędu lub użycia instrukcji break (ta instrukcja przerywa wykonywanie wszystkich rodzajów pętli, również pętli for I while). Poniżej przykład z użyciem tej czarnej owcy.
> # pętla repeat nie ma określonego warunku stopu, przerwać ją może
wywołanie polecenia break lub interwencja użytkownika
> repeat {
+ catCuda sie czy nłe?\n")
+ if (runif(1)<0.1)
+ break + }
uda sie czy nie? uda sie czy nie?
Instrukcję break można wykorzystywać w każdym rodzaju pętli, podobnie w każdej pętli można wykorzystywać instrukcję next. Pierwsza przerywa działanie pętli, druga powoduje przerwanie wykonywania aktualnej iteracji pętli oraz przejście do kolejnej iteracji.
Często w dużych programach pewne fragmenty kodu powtarzają się wielokrotnie i/iub są używane w różnych miejscach naszego programu. Czasem należy wykonać pewien schemat instrukcji, być może z niewielką różnicą w argumentach. W takich sytuacjach wygodnie jest napisać funkcję, która uprości program i poprawi jego czytelność. Generalnie rzecz biorąc zamykanie kodu w funkcjach jest dobrym zwyczajem, umożliwia tzw. reużywalność kodu, a tym samym wpływa na zmniejszenie liczby błędów, które zawsze gdzieś w kodzie się znajdą. Jest wiele wskazówek jak pisać dobre funkcje, ponieważ jednak nie jest to podręcznik do informatyki poprzestanę na dwóch uwagach. Funkcje powinny być tak tworzone, by nie korzystały ze zmiennych globalnych (parametry do działania powinny być przekazane poprzez argumenty, używanie zmiennych globalnych najczęściej prowadzi do trudnych w wykryciu błędów). Funkcje powinny być możliwie krótkie, ułatwi to ich modyfikacje i śledzenie. Jeżeli jakaś funkcja znacznie się rozrosła, to z pewnością można i warto podzielić ją na mniejsze funkcje. Poniżej przedstawiamy schemat deklaracji funkcji.
function(listaArgumentow) instr
Instrukcje instr można zastąpić blokiem instrukcji. Lista argumentów funkcji może być pusta, poniżej zamieszamy przykład deklaracji i wykonania funkcji bez argumentów. Funkcje w języku R są traktowano jak zwykle obiekty. Konsekwencje takiego rozwiązania zostaną szczegółowo przedstawione później. Poniżej przykład.