Skocz do zawartości

Pętla for-each


Rekomendowane odpowiedzi

  • Administratorzy

Dzisiaj na http://www.gmlscripts.com/forums/viewtopic.php?id=1911 natknąłem się na przykład pętli foreach dla GM oraz ds_list. Zaciekawiło mnie na czym polega myk i okazało się, że jest to bardzo prosta sprawa - GM działa także gdy pomijamy średniki, wiec można ten fakt wykorzystać.

 

Zgodnie z dokumentacją Game Makera:

 

for (<wyrazenie1>; <warunek>; <wyrazenie2>) <wyrazenie3>

Kroki: Pierwsze wyrażenie jest wykonywane. Sprawdzany jest warunek - jeśli jest prawidłowy, wykonywane jest wyrazenie3, potem wyrazenie 2 i wracamy do kolejności warunek-wyrazenie3-wyrazenie2 tak długo, jak warunek zwraca prawdę

 

Jak widzicie, nigdzie nie jest napisane, że wyrazenie1 musi ustawiać jakąś zmienną, a wyrazenie2 zwiększać/zmniejszać jej wartość. Co więcej - warunek nie musi być znakiem mniejszości czy większości. Napisane jest tylko, że wykonywanie trwa tak długo, jak warunek jest prawdziwy. W takim razie, wystarczy tu wstawić coś, co będzie nam zwracać prawdę lub fałsz - zmienną, lub funkcję. W ten oto sposób powstała pętla foreach. Pomysł jak już wspomniałem nie jest mój, natomiast wersja do obsługi tablic zamiast list jest już jak najbardziej moja (ponieważ w pracy nie mam pełnej wersji Game Makera, nie miałem dostepu do ds_list).

 

SKRYPTY

 

Pierwszy skrypt ustawia tablicę o rozmiarze 10, a potem w pętli foreach wyświetla jej elementy.

GML (test)
for (i=0; i<10; i+=1) {

tablica = i+1;

}

 

for( each('tablica',10) as key_value()) {

show_message(string(key) + '[' + string(value) +']');

}

 

GML (each)
if !variable_global_exists('as') {

globalvar as,eachVar,eachSize,key,value; //globalne

as = true;

}

 

eachVar = argument0; // referencja na tablice

eachSize = argument1;

key = -1;

 

key_value();

GML (keyvalue)
if key < eachSize - 1 {

key += 1;

value = variable_local_array_get(eachVar, key);

} else {

as = false;

key = -1;

value = -1;

eachVar = -1;

eachSize = -1;

}

Ha!

 

Jak to działa?

 

jak widzicie, mamy pętlę:

    for( each('tablica',10) as key_value()) {
        show_message(string(key) + '[' + string(value) +']');
    }

 

Tak naprawdę jest to normalna pętla for, tylko brakuje średników (bo GM ich nie wymaga).

GML
for( each('tablica',10); as; key_value())

 

funkcja each definiuje (jeśli nie istnieje) globalną zmienną "as" (jako globalvar, dlatego nie trzeba pisać global. z przodu), oraz kilka innych globalnych zmiennych które są nam tu potrzebne - key i value będą miały aktualny klucz i wartość tablicy. Zgodnie z dokumentacją, pierwsze wyrażenie jest przetwarzane raz.

Wyrażenie drugie jest sprawdzane. Nasza globalna as ma wartość true, zatem wyrażenie jest prawdziwe i wykonywane jest wyrazenie3 - czyli ciało pętli. Potem wracamy do wyrazenia2 - które zwiększa nam iterację, a przy okazji sprawdza, czy dochodzimy do konca tablicy - jeśli tak, to ustawi nam as na false.

Następnie znów sprawdzany jest warunek - jeśli as == false, no to pętla przestaje działać.

 

Takie proste, a dopiero teraz to odkryłem!

Odnośnik do komentarza
Udostępnij na innych stronach

  • Administratorzy

Z racji, że w GM nie ma tablic asocjacyjnych, to na normalnych tablicach tylko nieznacznie skraca zapis, ale w przypadku ds_list i ds_map - zaoszczędza sporo kodu - ofc tą funkcjonalność trzeba sobie dopisać, ale to zrobię dziś w domu i wrzucę na stronę jako przykład :)

 

http://4programmers.net/C_sharp/Foreach

http://php.net/manual/en/control-structures.foreach.php

Odnośnik do komentarza
Udostępnij na innych stronach

Jakoś niewydajne mi się by było to użyteczne przy większych produkcjach. Wydajność ostro leży.

 

GML
for( i = 0; i < 20000; i += 1 )

{

tekst = string(i);

}

 

 

 

 

 

// test -------------------------------------------------

a='';

time = current_time;

 

for( each('tekst',20000) as key_value())

{

a += value;

}

 

 

show_message( "foreach: " + a + "##" + string( current_time - time ) + " ms" );

 

a='';

time = current_time;

 

for( i = 0; i < 20000; i += 1 )

{

a += tekst;

}

 

 

show_message( "for: " + a + "##" + string( current_time - time ) + " ms" );

 

U mnie forech 875 ms, for 172 ms

Odnośnik do komentarza
Udostępnij na innych stronach

  • Administratorzy

Nigdzie nie napisałem, że dla tablic jest to szybsze. variable_local_array_get zjada większość tego czasu :) W przypadku stuktur danych (ds_) będzie to już praktycznie żadna różnica, ale za to jaka wygoda :) Będę miał dostęp do pełnego GM, dopiszę brakującą resztę i pogadamy :)

Odnośnik do komentarza
Udostępnij na innych stronach

  • Administratorzy

Proszę, teraz działa z tablicami, ds_list i ds_map :)

 

https://gmclan.org/up23_3_foreach.html

 

Zaznaczam jednak, że to wciąż bardziej ciekawostka bo te same zadania tradycyjną metodą są dużo szybsze.

Odnośnik do komentarza
Udostępnij na innych stronach

Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

Zarejestruj nowe konto

Załóż nowe konto. To bardzo proste!

Zarejestruj się

Zaloguj się

Posiadasz już konto? Zaloguj się poniżej.

Zaloguj się
  • Ostatnio przeglądający   0 użytkowników

    • Brak zarejestrowanych użytkowników przeglądających tę stronę.
×
×
  • Dodaj nową pozycję...