Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Problem z funkcją rekurencyjną.
Forum PHP.pl > Forum > PHP
jareqpl
Witajcie, mam problem z napisaniem takiej funkcji która przeszłaby taką tablicę:
array(
'cos' => array( 'cos2' => 3, 'imie' => 'maciek' ),
'costam' => array('liczby' => array('pierwsza' => 1, 'druga' => 2), 'liczba2' => 3)
);

chcialbym zeby funkcja przyjęła tablice o dowolnej "głębokości" i wyswietlila cos takiego
array(
'cos.cos2' => 3,
'cos.imie' => 'maciek',
'costam.liczba.pierwsza' => 1,
'costam.liczba.druga' => '2',
'costam.liczba2' => 3
);

Oczywiście dane wymyślone teraz.

Próbowałem już różnych metod ale bardzo się w tym gubię.
Nie miałem do czynienia z rekurencją do tej pory. Mógłby ktoś pomóc?
jareqpl
dzięki wielkie, ja rozumiem jak działają funkcje ale z tym nie mogę sobie poradzić. Czytałem o funkcjach rekurencyjnych - proste umiem napisać. Ale to jest nieco bardziej złożone.
!*!
  1. funkcja()
  2. {
  3. $nowa = null;
  4. foreach()
  5. if()
  6. {
  7. // sprawdzasz czy wartosc tablicy to array, jak tak dodajesz do zmiennej $nowa .= $key
  8. // i wykonujesz funkcje jeszce raz, a jak nie leciesz dalej po tablicy
  9. }
  10. return $nowa;
  11. }

Tak w skrócie.
jareqpl
Próbowałem takiego rozwiązania jak ty, wynik wygląda tak że cała tablica jest połączona kropkami.
$tab[cos.cos2.cos.imie.costam.liczba.pierwsza.costam.liczba.druga.costam.lic
zba2] itd...
Próbowałem już wielu rozwiązań, chyba z 3 godziny się z tym bawie. Nie wiem dlaczego ja tego nie mogę ogarnąć smile.gif
Lag mózgu chyba.
shinuexx
  1. function recursiveToSingle($array,&$out = array(),$parentKey = ''){
  2. $fun = __FUNCTION__;
  3. foreach($array as $key => $val){
  4. if(is_array($val))
  5. $fun($val,$out,$parentKey.$key.".");
  6. else
  7. $out[$parentKey.$key] = $val;
  8. }
  9. }
  10.  
  11. $t = array(
  12. 'cos' => array(
  13. 'cos2' => 3,
  14. 'imie' => 'maciek'
  15. ),
  16. 'costam' => array(
  17. 'liczby' => array(
  18. 'pierwsza' => 1,
  19. 'druga' => 2
  20. ),
  21. 'liczba2' => 3
  22. )
  23. );
  24. recursiveToSingle($t,$out);
  25. print_vars($t,$out);

out:
Kod
array[2]
(
    [cos] => array[2]
    (
        [cos2] => integer (3)
        [imie] => string[6] ("maciek")
    )
    [costam] => array[2]
    (
        [liczby] => array[2]
        (
            [pierwsza] => integer (1)
            [druga] => integer (2)
        )
        [liczba2] => integer (3)
    )
)
array[5]
(
    [cos.cos2] => integer (3)
    [cos.imie] => string[6] ("maciek")
    [costam.liczby.pierwsza] => integer (1)
    [costam.liczby.druga] => integer (2)
    [costam.liczba2] => integer (3)
)


nie tylko rekurencja ale i referencja jest tu potrzebna ponieważ tablica ma się zwiększać nawet w podtablicach.
lukaskolista
Referencja wcale nie jest potrzebna. Twoj kod przerobiony tak, aby referencji nie uzywac:
  1. function recursiveToSingle($array, $out = array(), $parentKey = '')
  2. {
  3. $fun = __FUNCTION__;
  4.  
  5. foreach($array as $key => $val)
  6. {
  7. if(is_array($val))
  8. {
  9. $out += $fun($val,$out,$parentKey.$key.".");
  10. }
  11. else
  12. {
  13. $out += array($parentKey.$key => $val);
  14. }
  15. }
  16.  
  17. return $out;
  18. }
  19.  
  20. $t = array(
  21. 'cos' => array(
  22. 'cos2' => 3,
  23. 'imie' => 'maciek'
  24. ),
  25. 'costam' => array(
  26. 'liczby' => array(
  27. 'pierwsza' => 1,
  28. 'druga' => 2
  29. ),
  30. 'liczba2' => 3
  31. )
  32. );
  33.  
  34. $out = recursiveToSingle($t);
  35. echo '<pre>';
  36. print_r($out);
IMO im mniej referencji (poza obiektowoscia), tym lepiej.

PS.
cos formatowanie kodu dziwnie dziala, kod nie wyglada tak, jak w oryginale, ale trudno.
Shido
Cytat(shinuexx @ 26.07.2012, 20:00:52 ) *
Kod
array[2]
(
    [cos] => array[2]
    (
        [cos2] => integer (3)
        [imie] => string[6] ("maciek")
    )
    [costam] => array[2]
    (
        [liczby] => array[2]
        (
            [pierwsza] => integer (1)
            [druga] => integer (2)
        )
        [liczba2] => integer (3)
    )
)
array[5]
(
    [cos.cos2] => integer (3)
    [cos.imie] => string[6] ("maciek")
    [costam.liczby.pierwsza] => integer (1)
    [costam.liczby.druga] => integer (2)
    [costam.liczba2] => integer (3)
)

Taki efekt, bądź podobny, daje przecież:
  1. echo('<pre>');
  2. print_r($tablica);
  3. echo('</pre>');

lukaskolista
Shido:
niestety nie, tutaj chodzi o konwersje tablicy wielowymiarowej do jednowymiarowej laczac klucze kropka.
Shido
A dobra, mój błąd nie doczytałem...
!*!
Cytat
cos formatowanie kodu dziwnie dziala, kod nie wyglada tak, jak w oryginale, ale trudno.

Działa dobrze, tylko w swoim edytorze masz tabulacje zamiast spacji i jak zawsze w takich wypadkach robi się burdel tongue.gif
shinuexx
lukaskolista:
w sumie zapomniałem że można użyć '+';P

Swoją drogą to przydatny kod.
lukaskolista
Do czego sie przyda? Jak dla mnie jest kompletnie bezuzyteczny, poniewaz w kluczach tablic asocjacyjnych mozna uzywac kropki, a wtedy cala struktura tablicy zostanie zaburzona.
rocktech.pl
Witam.

Poc kombinować SPL i RecursiveArrayIterator
  1. $myArray = array(
  2. 'cos' => array('cos2' => 3, 'imie' => 'maciek'),
  3. 'costam' => array('liczby' => array('pierwsza' => 1, 'druga' => 2), 'liczba2' => 3)
  4. );
  5.  
  6. $iterator = new RecursiveArrayIterator ( $myArray );
  7. ...
lukaskolista
My nie kombinujemy, podczas iteracji tablicy przez iterator trzeba wykonac dokladnie te same operacje, ktore wykonywane sa w ciele funckji rekurencyjnej. W tym temacie nie chodzi o to, aby rekursywnie iterowac tablice, tylko zeby z tablicy wielowymiarowej zrobic jednowymiarowa.
jareqpl
Dziękuje wam bardzo. Nie wiem dlaczego nie mogłem tego zrobić, to był pierwszy problem z którym się tak długo borykałem od kąd programuje. Jeszcze raz dziękuje i pozdrawiam.
erix
~lukaskolista, owszem, to jest kombinowanie, bo stwarzacie koło na nowo.

Iteratory albo array_walk_recursive, to najlepsze rozwiązanie tego problemu.
lukaskolista
Nie rozumiesz jednej rzeczy: my nie narzucamy rozwiazan, tylko przedstawiamy sposob. Kazdy sobie zrobi jak chce. Ty uwazasz, ze powinno byc inaczej, ktos inny uwaza ze jest ok, a znajdzie sie na pewno osoba, ktora by to jeszcze inaczej zrobila. W jezykach programowania jedna rzecz da sie zrobic na wiele konkurencyjnych sposobow. Wybor odpowiedniego zalezy od konkretnego programisty.
erix
Cytat
W jezykach programowania jedna rzecz da sie zrobic na wiele konkurencyjnych sposobow. Wybor odpowiedniego zalezy od konkretnego programisty.

A złożoność obliczeniowa, to została w podręcznikach?
lukaskolista
Wiec prosze, policz mi zlozonosc, przedstaw wyniki dla tych 2 rozwiazan i bedziemy dyskutowac dalej.
erix
Do tego nie trzeba liczyć - wystarczy benchmark na każde z rozwiązań.

A podejrzewam na 90%, że funkcje wbudowane będą szybsze od ręcznej implementacji przez rekurencję.
lukaskolista
A ja nie podejrzewam, jak przedstawisz konkretne wyniki to przyznam Ci racje. Nie lubie gdybania.
erix
To sprawdź. [;

Ja teraz na to czasu nie mam.
lukaskolista
Ale to Ty mi zarzucasz bezsensownosc kodu i jego duza zlozonosc, wiec to Ty powinienes to udowodnic - ja tez nie mam czasu.

Skoro nie chcesz udowodnic, to ja to juz zrobie:
lukaskolista: 1.962198972702s
roctech + erix (RecursiveArrayIterator): 5.3361186981201s
Wyniki podane w sekundach dla 100 000 wykonan. Nie bede juz nawet sprawdzal ilosci zuzytej pamieci operacyjnej, bo obiekty iteratora waza swoje, a funkcja rekurencyjna nie.

Wiec nastepnym razem sprawdz, czy masz racje zanim uznasz, ze ja masz.
jareqpl
Ale ja wiem że można było użyć array_walk_recursive tylko że miałem duży problem z napisaniem tej funkcji i chciałem się dowiedzieć jak to zrobić żeby się czegoś więcej nauczyć. Dlatego poprosiłem o wyjaśnienie. Pozdrawiam smile.gif
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.