![]() |
![]() ![]() |
![]() |
![]()
Post
#1
|
|
![]() Grupa: Zarząd Postów: 2 277 Pomógł: 6 Dołączył: 27.12.2002 Skąd: Wołów/Wrocław ![]() |
Odkąd poznałem możliwości SPL jestem pod dużym wrażeniem możliwości podsuwanych tam pomysłow, i coraz częściej staram się z nich korzystać.
Zacząłem stosować iteratory, i rzeczywiście - okazały się w wielu przypadkach bardzo przydatne, zmiejszając ilość (chyba ![]() Zastanawiam się jednak, czy istnieje jakiś prosty sposób na tworzenie iteratoró w nieco bardziej złożonych przypadkach. Zacznijmy od jakiegoś prostego przypadku. Np. mamy 2 tablice, a potrzebna jest nam jedna, w której znajdują się wszystkie kombinacje elementów z tych 2 powyższych (czyli każdy z każdym). Normalnie rozwiązanie bardzo proste. Dwa foreach, jeden drugim, i generowanie tablicy wynikowej.
Jednak w ten sposób przechowujemy całą tą tablicę zupełnie niepotrzebnie, bo tak naprawdę do dalszego działania programu będziemy potrzebowali 1, kolejny jej element w danym momencie.... Oczywiście - nawet na chłopski rozum można napisać odpowiedni iterator, wymaga jednak całkiem złożonego algorytmu sprawdzania kolejnych elementów i ich zwracania. A problem wydaje mi się na tyle standardowy, że powinny być jakieś "standardowe" rozwiązania - chyba że mam po prostu zaćmę i czegoś oczywistego nie udało mi sie dotychczas zauważyć... ![]() // ps. i nie próbujcie mi odpowiedzieć, że są jakieś standardowe funkcje do łączenia tablic, bo normalnie ... zamorduję ![]() -------------------- "Niezależnie od tego, jakie masz osiągnięcia, ktoś Ci pomaga..."
|
|
|
![]()
Post
#2
|
|
Administrator PHPedia.pl Grupa: Developerzy Postów: 1 102 Pomógł: 2 Dołączył: 14.09.2003 Ostrzeżenie: (0%) ![]() ![]() |
Trochę to zagmatwane, ale czy chcesz połączyć 2 tabele ? A czy przypadkiem nie można wykorzystać array_merge" title="Zobacz w manualu PHP" target="_manual ?
-------------------- |
|
|
![]()
Post
#3
|
|
![]() Grupa: Zarejestrowani Postów: 657 Pomógł: 2 Dołączył: 15.08.2003 Skąd: Łódź Ostrzeżenie: (0%) ![]() ![]() |
hmm... odpowiednie interfejsy deklarujesz i juz na obiekcie bedacym iteratorem mozes stosowac funkcje array_*
-------------------- |
|
|
![]()
Post
#4
|
|
![]() Grupa: Zarejestrowani Postów: 521 Pomógł: 0 Dołączył: 3.11.2003 Skąd: 3city Ostrzeżenie: (0%) ![]() ![]() |
Standardowego rozwiązania nie będzie raczej, bo ktoś musiałby po prostu napisać odpowiedni iterator i tyle. A samo napisanie takiego iteratora jest proste. Przyjmuje w konstruktorze 2 argumenty (tablice), dla każdej robi count() i zapamiętuje, ma 2 liczniki pozycji i inkrementuje tak żeby przelecieć wszystkie kombinacje. Jaki tam złożony algorytm...
A wszystkie pomysły z array_* są bez sensu bo właśnie nie chcemy łączyć tych tablic i po to używamy iteratora, prawda? |
|
|
![]()
Post
#5
|
|
![]() Grupa: Zarząd Postów: 2 277 Pomógł: 6 Dołączył: 27.12.2002 Skąd: Wołów/Wrocław ![]() |
oczywiście, hawk.
Mimo to miałem nadzieję, że żucicsz jakimś ciekawym linkiem o tej tematyce. Ale fakt - faktem. Po napisaniu nie wygląda to już nawet tak groźnie, i choć ciągle się zastanawiam, czy napisane jest optymalnie (jakoś dużo tych warunków mi się zrobiło :/ ) to jednak działa w pełni zgodnie z założeniami. Dla wątpiących: ![]()
mile widziane oczywiście propozycje poprawy tego kodu... //ps. a jeśli ktoś się zastanawia, czy jest sens tworzenia taiej ilości kodu, zamiast zaprezentowanych powyżej dwóch pętli - niech wyobrazi sobie, że ten iterator nie pracuje na 2 tylko na np. 4 tablicach. I policzy - jakiej wielkości byłaby tablica wynikowa.... -------------------- "Niezależnie od tego, jakie masz osiągnięcia, ktoś Ci pomaga..."
|
|
|
![]()
Post
#6
|
|
![]() Grupa: Zarejestrowani Postów: 521 Pomógł: 0 Dołączył: 3.11.2003 Skąd: 3city Ostrzeżenie: (0%) ![]() ![]() |
Kod jest dobry. Nic dodać nic ująć.
Taki przykład z dwiema tablicami faktycznie może wydawać się przerośnięty, ale tak już jest z przykładami. Wystarczy wymyśleć jakieś bardziej zakręcone kryteria łączenia tablic i już proporcje się wyrównują. Dla lepszej ilustracji, podam iterator, który kiedyś wymyśliłem. Co prawda w Javie, ale to bez znaczenia. Niech ktoś to spróbuje zrobić kodem proceduralnym ![]() 1) Jest sobie drzewko w pamięci. Robimy prosty (?) iterator depth-first. No, taki prosty to on nie jest, ale wystarczy poszukać kodu - standard. 2) Robimy interfejs Chooser... Kod public interface Chooser { public boolean choose(TreeElement te); } ...który po prostu dostaje element i mówi czy mu się podoba, czy nie. 3) Robimy ChoosingIterator... Kod class ChoosingIterator implements Iterator { public ChoosingIterator(Iterator i, Chooser c) { //... } //... } ... który filtruje output zwykłego iteratora drzewkowego wykorzystując Chooser. 4) Skutek? Zrobiliśmy z tego w programie operującym na wielkich drzewach rozszerzalny system wyszukiwania. Piszesz jedną klasę implementującą Chooser, system wpina ci to w menu i już masz najgłupsze nawet kryteria wyszukiwania z Find / Find next / przewijaniem na początek dokumentu itd. Wyszło off-topic, ale to tak w zastępstwie linka, którego dopominał się DeyV. ![]() |
|
|
![]()
Post
#7
|
|
![]() Grupa: Zarząd Postów: 2 277 Pomógł: 6 Dołączył: 27.12.2002 Skąd: Wołów/Wrocław ![]() |
dla zainteresowanych dodam, żę bardzo podobny to tego, co podał Hawk, przykład obsługi drzew w oparciu o iterator jest proponowany również przez SPL.
Zainteresowanych odsłym do kodu Iteratora struktury katalogów, w którym bardzo łatwo można zobaczyć sposó pisania filtrów, ograniczających wyświetlanie informacji. Np. usuwanie . i .. lub wszystkich folderów zaczynających sie na aa ![]() Jedyne co w tym wszystkim odrobinę boli, to to, że na potrzeby drzewka tworzy się wiele zagłębiających się obiektów, czyli odpowiednik bardzo nielubianego przez wielu w pisaniu strukturalnym, kod rekurencyjny. -------------------- "Niezależnie od tego, jakie masz osiągnięcia, ktoś Ci pomaga..."
|
|
|
![]()
Post
#8
|
|
![]() Grupa: Zarejestrowani Postów: 521 Pomógł: 0 Dołączył: 3.11.2003 Skąd: 3city Ostrzeżenie: (0%) ![]() ![]() |
Zawsze możesz sobie napisać iterator drzewek/katalogów, który bazuje na iteracji, nie na rekurencji.
A skoro wszystko i tak bazuje na interfejsach, możesz sobie podpiąć swój iterator w miejsce RecursiveDirectoryIterator, i reszta kodu tego nie zauważy. Chociaż DirectoryFilterDots niestety wymaga RecursiveIterator. Tutaj IMHO Boerger źle to zrobił, bo DirectoryIterator nie implementuje RecursiveIterator. Ale pewnie miał swoje powody. |
|
|
![]()
Post
#9
|
|
![]() Grupa: Zarejestrowani Postów: 5 Pomógł: 0 Dołączył: 8.02.2005 Ostrzeżenie: (0%) ![]() ![]() |
Hello World...
przeprowadzając testy (w pętli : x10 000) wyszło że: -> system z iteracją: śr. czas wykonania jednej pętli wynosi 0,0005207s (pamięć >32MB) -> pętla śr. czas: 0,0002610s (pamięć >31MB) tak więc różnica w szybkości wynosi 199,5%... ![]() "wąskie gardło" ?
z 2 robią się 4... ![]() Cytat //ps. a jeśli ktoś się zastanawia, czy jest sens tworzenia taiej ilości kodu, zamiast zaprezentowanych powyżej dwóch pętli - niech wyobrazi sobie, że ten iterator nie pracuje na 2 tylko na np. 4 tablicach. I policzy - jakiej wielkości byłaby tablica wynikowa.... z tego co widzę, klasa GenerateNames jest przystosowana do obsługi tylko 2 tablic, czyli żeby obsłużyć np. 4 tablice trzeba klasę znacznie rozbudować ? -------------------- priv: jestem uczniem technikum budowlanego (aktualnie 3 rok tej męki a raczej kompletnego braku zainteresowania tematem)
|
|
|
![]()
Post
#10
|
|
![]() Grupa: Zarejestrowani Postów: 312 Pomógł: 0 Dołączył: 29.12.2004 Ostrzeżenie: (0%) ![]() ![]() |
Cytat // ps. i nie próbujcie mi odpowiedzieć, że są jakieś standardowe funkcje do łączenia tablic, bo normalnie ... zamorduję array_combine ![]() a iteracja to ciekawy temat, całkiem niedawno skróciłem tym sposobem dużą część kodu, w połączeniu z wbudowanymi funkcjami operującymi na tablicach można dużo zdziałać. -------------------- ![]() ![]() |
|
|
![]()
Post
#11
|
|
![]() Grupa: Przyjaciele php.pl Postów: 5 724 Pomógł: 259 Dołączył: 13.04.2004 Skąd: N/A Ostrzeżenie: (0%) ![]() ![]() |
@ennics: Ale array_combine nie utworzy tego co chcial osiagnac.
@DeyV: moj pierwszy Iterator dziala podobnie jak twoj 'GenerateNames', z tym ze u ciebie beda problemu z tablicami indeksowanymi inaczej niz intami poczawszy od zera (dlatego ja wykonuje przeindeksowanie). Moje iteratory: Drugi 'Kombinacje_Tablic_2' uzywa funkcji next(), current(), reset() itd, sa one wolniejsze i uniemozliwiaja uzywanie elementow pustych ( 0, "" ). Pierwszy 'Kombinacje_Tablic' przeindeksowuje tablice tak zeby byly indeksowane integerami (szybszy dostep do danych, kontrola indeksow za pomoca liczb -- zapamietuje ilosc elementow i indeks aktualnego , brak bugu z pustymi elelmentami) Dla 1000 powtorzen (samo przelecenie tablic, bez printowania indeksow i elementow): - 2xzagniezdzony foreach: 0.25s - pierwszy iterator: 0.89s - drugi iterator: 1.09s Wnioski: foreach najszybsze (zaraz sprawdze dla wiekszej ilosci tablic), przeindeksowanie tablic przyspiesza iteracje.
-------------------- Nie lubię jednorożców.
|
|
|
![]()
Post
#12
|
|
![]() Grupa: Zarząd Postów: 2 277 Pomógł: 6 Dołączył: 27.12.2002 Skąd: Wołów/Wrocław ![]() |
antao - ciekawy test, jednak nie do końca odpowiedni.
Zobacz, że w moim przykładzie (z 2 pętlami) tworzona była 3 tablica - do wykorzystania później. Dopiero tą tablicę można by potraktować foreach, i dopiero to byłby dokładny odpowiednik kodu z iteratorem. A wtedy zużycie pamięci się zwiększy conajmnie 4 krotnie. (jak sądzę ![]() Cytat "wąskie gardło" ? ... z 2 robią się 4... smile.gif Jednak nie. php ma bardzo ciekawą technologię kopiowania tablic on edit. Oznacza to, że tak długo, jak któraś z tych tablic nie zostanie wyedytowana, tak dlugo w pamięci przechowywana jest tylko 1 jej instancja, a my odwołujemy ię niejako do jej referencji. Dopiero podczas wprowadzania zmian w którejś z nich - tworzą się osobne kopie. Jeśli masz php postawione na linuksie i xdebug - polecam przeprowadzenie dokładnego testu - ja widziałem kiedyś taki, i byłem naprawdę zaskoczony tym, jak mało pamięci zostało zużyte na skopiowanie tablicy. Cytat z tego co widzę, klasa GenerateNames jest przystosowana do obsługi tylko 2 tablic, czyli żeby obsłużyć np. 4 tablice trzeba klasę znacznie rozbudować ? Tak naprawdę - wystarczły dodać liczniki dla każdej z tych tablic, zmierzyć ich wielkość, i odpowiednio rozbudować warunek. hawk - temat - rzeka - cieszę się jednak, że udało nam sie tu zainteresować nim kilka kolejnych osób. -------------------- "Niezależnie od tego, jakie masz osiągnięcia, ktoś Ci pomaga..."
|
|
|
![]()
Post
#13
|
|
![]() Grupa: Przyjaciele php.pl Postów: 5 724 Pomógł: 259 Dołączył: 13.04.2004 Skąd: N/A Ostrzeżenie: (0%) ![]() ![]() |
At last!
Dla tych 5ciu tablic: 0.08 s (@ PII 350), ktos chce porownac foreach'e ![]() Oczywiscie dziala prawidlowo dla 0, 1ej i dwoch tablic. -------------------- Nie lubię jednorożców.
|
|
|
![]() ![]() |
![]() |
Aktualny czas: 19.08.2025 - 09:08 |