Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > it.comp.www.php > #20939 > unrolled thread

ritornare una list mixed

Started bySandro kensan <kensan@kensan.it>
First post2016-06-17 18:48 +0200
Last post2016-06-18 12:29 -0700
Articles 11 — 3 participants

Back to article view | Back to it.comp.www.php


Contents

  ritornare una list mixed Sandro kensan <kensan@kensan.it> - 2016-06-17 18:48 +0200
    Re: ritornare una list mixed fmassei@gmail.com - 2016-06-17 10:26 -0700
      Re: ritornare una list mixed Sandro kensan <kensan@kensan.it> - 2016-06-17 20:49 +0200
        Re: ritornare una list mixed fmassei@gmail.com - 2016-06-17 12:11 -0700
          Re: ritornare una list mixed Sandro kensan <kensan@kensan.it> - 2016-06-17 22:01 +0200
            Re: ritornare una list mixed fmassei@gmail.com - 2016-06-17 16:51 -0700
    Re: ritornare una list mixed Alessandro Pellizzari <shuriken@amiran.it> - 2016-06-17 20:34 +0000
      Re: ritornare una list mixed Sandro kensan <kensan@kensan.it> - 2016-06-18 00:18 +0200
      Re: ritornare una list mixed fmassei@gmail.com - 2016-06-17 17:26 -0700
        Re: ritornare una list mixed Alessandro Pellizzari <shuriken@amiran.it> - 2016-06-18 16:28 +0000
          Re: ritornare una list mixed fmassei@gmail.com - 2016-06-18 12:29 -0700

#20939 — ritornare una list mixed

FromSandro kensan <kensan@kensan.it>
Date2016-06-17 18:48 +0200
Subjectritornare una list mixed
Message-ID<dsinv7F5lpjU1@mid.individual.net>
Ho una funzione ricorsiva che usa come valori di ritorno un array di
stringhe e un array di nodi di un DOM document, gli array sono della
stessa lunghezza. Come posso ritornarli nella mia funzione ricorsiva?

function recursively_find_text_nodes($dom_element) {
  global $node;
  $return = array();

  foreach ($dom_element->childNodes as $dom_child) {
     switch ($dom_child->nodeType) {
	case XML_TEXT_NODE:
	  if (trim($dom_child->nodeValue) !== '') {
			$return[] = $dom_child->nodeValue;
			$node[] = $dom_child;
          }
	break;
	case XML_ELEMENT_NODE:
	  $return = array_merge($return, recursively_find_text_nodes(
$dom_child ));
	break;
     }
   }
   return $return;
}

Vorrei fare un return array($return, $node); e poi un list($a, $b) =
recursively_find_text_nodes($dom_element);

Quindi un:
$return = array_merge($return, recursively_find_text_nodes( $dom_child ));
===>
modifica di conseguenza.

Può funzionare?
-- 
Sandro kensan www.kensan.it & www.qiqi.it geek site
Saluto gli agenti della NSA - Hello NSA - www.nsa.gov

[toc] | [next] | [standalone]


#20940

Fromfmassei@gmail.com
Date2016-06-17 10:26 -0700
Message-ID<691b2344-a346-4d13-97bc-44ba68fa1fc8@googlegroups.com>
In reply to#20939
On Friday, June 17, 2016 at 12:48:41 PM UTC-4, Sandro kensan wrote:
> Ho una funzione ricorsiva che usa come valori di ritorno un array di
> stringhe e un array di nodi di un DOM document, gli array sono della
> stessa lunghezza. Come posso ritornarli nella mia funzione ricorsiva?
> 
> <snip>
>

Perché non puoi direttamente usare XPath? :)
Questa funzione che deve fare? ;)

Ciao!

[toc] | [prev] | [next] | [standalone]


#20941

FromSandro kensan <kensan@kensan.it>
Date2016-06-17 20:49 +0200
Message-ID<dsiv17Faq2hU1@mid.individual.net>
In reply to#20940
On 17/06/2016 19:26, fmassei@gmail.com wrote:

> Perché non puoi direttamente usare XPath? :)
> Questa funzione che deve fare? ;)

Non so molto usare il DOM che è molto utile sapere gestire e quindi sto
facendo pratica esclusivamente col DOM.

In generale è utile percorrere tutto l'albero: è l'abc. Nel mio caso si
tratta di trovare tutti i nodi che hanno del testo come foglie. Mi serve
memorizzare sia il testo che il nodo in modo da potere poi modificare il
testo.

Ma in generale con le funzioni ricorsive c'è il problema di fare entrare
i dati e di farli uscire e questo è un caso tipico. Chiedo se si può
risolvere.

-- 
Sandro kensan www.kensan.it & www.qiqi.it geek site
Saluto gli agenti della NSA - Hello NSA - www.nsa.gov

[toc] | [prev] | [next] | [standalone]


#20942

Fromfmassei@gmail.com
Date2016-06-17 12:11 -0700
Message-ID<1a8490fd-1a38-47c9-aa68-c7efb6527a2b@googlegroups.com>
In reply to#20941
On Friday, June 17, 2016 at 2:49:13 PM UTC-4, Sandro kensan wrote:
> On 17/06/2016 19:26, fmassei@gmail.com wrote:
> 
> > Perché non puoi direttamente usare XPath? :)
> > Questa funzione che deve fare? ;)
> 
> Non so molto usare il DOM che è molto utile sapere gestire e quindi sto
> facendo pratica esclusivamente col DOM.
> 

Ah OK, se è per far pratica.. :)

> In generale è utile percorrere tutto l'albero: è l'abc. Nel mio caso si
> tratta di trovare tutti i nodi che hanno del testo come foglie. Mi serve
> memorizzare sia il testo che il nodo in modo da potere poi modificare il
> testo.
> 

Questa non la capisco.. perché devi memorizzare (cosa poi?)?
Non puoi passare alla funzione ricorsiva una callback che fa quello che deve
fare su ogni nodo? Altrimenti stai solo cambiando la rappresentazione dei
dati da albero (il DOM) a vettore (i tuoi array_merge), che è un passaggio
in più che non mi sembra tanto sensato..

> Ma in generale con le funzioni ricorsive c'è il problema di fare entrare
> i dati e di farli uscire e questo è un caso tipico. Chiedo se si può
> risolvere.
> 

Se vuoi linearizzare l'albero come stai facendo va bene. Non vedo a cosa mai
potrebbe servire, però.

Ciao!

[toc] | [prev] | [next] | [standalone]


#20943

FromSandro kensan <kensan@kensan.it>
Date2016-06-17 22:01 +0200
Message-ID<dsj385Faq2hU2@mid.individual.net>
In reply to#20942
On 17/06/2016 21:11, fmassei@gmail.com wrote:

> Ah OK, se è per far pratica.. :)

Si, serve per fare pratica ma ha anche un risvolto pratico: ho un
problema da risolvere e lo vorrei risolvere col DOM.

> Questa non la capisco.. perché devi memorizzare (cosa poi?)?
> Non puoi passare alla funzione ricorsiva una callback che fa quello che deve
> fare su ogni nodo?

Anche questa è una buona idea. Però dal punto di vista teorico mi piace
poco perché in caso di malfunzionamenti ho problemi col debug
soprattutto per me che il DOM lo mastico molto poco. Quindi preferisco
tenere separate le due fasi: trovo tutte le foglie di tipo testo,
modifico le foglie di tipo testo in un modo particolare.

> Altrimenti stai solo cambiando la rappresentazione dei
> dati da albero (il DOM) a vettore (i tuoi array_merge), che è un passaggio
> in più che non mi sembra tanto sensato..

è in più ma permette di separare.

> Se vuoi linearizzare l'albero come stai facendo va bene. Non vedo a cosa mai
> potrebbe servire, però.

All'atto pratico serve a questo:

http://www.kensan.it/articoli/Volantino.php

La cosa impressionate del php è che ti stupisce. Quello che chiedevo nel
mio primo post ho provato a realizzarlo e funziona! In pratica gli array
con elementi di tipo nodo di un DOM e di tipo string sono possibili. Non
credevo.


-- 
Sandro kensan www.kensan.it & www.qiqi.it geek site
Saluto gli agenti della NSA - Hello NSA - www.nsa.gov

[toc] | [prev] | [next] | [standalone]


#20946

Fromfmassei@gmail.com
Date2016-06-17 16:51 -0700
Message-ID<5762bf40-00c8-49bb-abcd-c011265b5eaf@googlegroups.com>
In reply to#20943
On Friday, June 17, 2016 at 4:01:13 PM UTC-4, Sandro kensan wrote:
> On 17/06/2016 21:11, fmassei@gmail.com wrote:
> > Questa non la capisco.. perché devi memorizzare (cosa poi?)?
> > Non puoi passare alla funzione ricorsiva una callback che fa quello che
> > deve fare su ogni nodo?
> 
> Anche questa è una buona idea. Però dal punto di vista teorico mi piace
> poco perché in caso di malfunzionamenti ho problemi col debug
> soprattutto per me che il DOM lo mastico molto poco. Quindi preferisco
> tenere separate le due fasi: trovo tutte le foglie di tipo testo,
> modifico le foglie di tipo testo in un modo particolare.
> 

Visto che stai giusto provando cose per conto tuo non entro nei dettagli,
però puntualizzo una cosa...

Dal "punto di vista teorico" passare una callback alla funzione ricorsiva è
esattamente come bisognerebbe fare :)
Lascia stare il fatto che è un albero: quando hai una struttura dati e devi
fare un'operazione su ogni elemento (una "map" nella terminologia lambda)
semplicemente la cicli. Può essere un array, un albero, un grafo o chissà
quale strana struttura, ma il concetto è lo stesso.
Se hai un vettore (un array) cosa fai, metti ognuno degli N elementi in N
variabili e chiami N volte la funzione, o fai un for? :) Allo stesso modo, se
hai un albero, che senso ha metterlo in un vettore quando puoi semplicemente
ciclarlo? :)

Magari ora ti sembra complicato perché non l'hai fatto mai, o non molto spesso,
ma ti garantisco che, specialmente nel debug, quando c'è un errore, è più
facile capire dov'è in una funzione sola che in due (l'errore è sulla funzione
ricorsiva che mi trasforma l'albero in array o su quella che fa le
trasformazioni su nodi?).

> > Altrimenti stai solo cambiando la rappresentazione dei
> > dati da albero (il DOM) a vettore (i tuoi array_merge), che è un passaggio
> > in più che non mi sembra tanto sensato..
> 
> è in più ma permette di separare.
> 

E' solo questione d'abitudine. Se vuoi provarci e scriverla con una callback,
vedrai che tutto il codice sarà soprendentemente (dico per te, io già ne sono
sicuro ;)) più chiaro!

Ciao!

[toc] | [prev] | [next] | [standalone]


#20944

FromAlessandro Pellizzari <shuriken@amiran.it>
Date2016-06-17 20:34 +0000
Message-ID<dsj563Fbsg9U1@mid.individual.net>
In reply to#20939
Il Fri, 17 Jun 2016 18:48:39 +0200, Sandro kensan ha scritto:

> Ho una funzione ricorsiva che usa come valori di ritorno un array di
> stringhe e un array di nodi di un DOM document, gli array sono della
> stessa lunghezza. Come posso ritornarli nella mia funzione ricorsiva?

Puoi sicuramente tornare un array (di array) misto. L'unica limitazione 
degli array di PHP è che le chiavi devono essere scalari, ma i valori 
possono essere qualsiasi cosa.

Ma io onestamente farei in modo diverso...
 
> function recursively_find_text_nodes($dom_element) {
>   global $node;
>   $return = array();
> 
>   foreach ($dom_element->childNodes as $dom_child) {
>      switch ($dom_child->nodeType) {
> 	case XML_TEXT_NODE:
> 	  if (trim($dom_child->nodeValue) !== '') {
> 			$return[] = $dom_child->nodeValue;
> 			$node[] = $dom_child;

Qui i due valori sono strettamente correlati.

Hai due possibilità, secondo me:

1- tornare solo il nodo, che tanto da lì puoi sempre recuperare il valore:
 $return[] = $domNode;

2- tornare ogni elemento come "sotto-array" che li contiene entrambi:
 $return[] = [$dom_child, $dom_child->nodeValue];

Questa seconda ti permette di fare

foreach (recursively_find_text_nodes($dom) as list($elem, value)) { ... }

(Non mi ricordo da che versione di PHP puoi usare "as list()")

> Può funzionare?

Se <strike>ti vuoi male</strike> vuoi vivere nel futuro, puoi usare i 
generatori:

function find_text_nodes($dom_element)
{
  foreach ($dom_element->childNodes as $dom_child) {
    switch ($dom_child->nodeType) {
      case XML_TEXT_NODE:
        if (trim($dom_child->nodeValue) !== '') {
          yield $dom_child;
        }
        break;
        case XML_ELEMENT_NODE:
          yield from find_text_nodes($dom_child);
	break;
    }
  }
}

foreach (find_text_nodes($elem) as $node) {
  ...
}

WARNING: codice non testato, scritto di getto, e richiede PHP7. :)

Questa versione ha il vantaggio che non tiene in memoria la lista di tutti 
i nodi e del loro contenuto, ma ne genera uno alla volta man mano che li 
consumi, quindi puoi potenzialmente parsare un HTML il doppio più grosso 
con la stessa quantità di RAM.

Bye.

[toc] | [prev] | [next] | [standalone]


#20945

FromSandro kensan <kensan@kensan.it>
Date2016-06-18 00:18 +0200
Message-ID<dsjba0Faq2hU3@mid.individual.net>
In reply to#20944
On 17/06/2016 22:34, Alessandro Pellizzari wrote:

> Puoi sicuramente tornare un array (di array) misto. L'unica limitazione 
> degli array di PHP è che le chiavi devono essere scalari, ma i valori 
> possono essere qualsiasi cosa.

infatti, ho provato e funziona perfettamente.

> Ma io onestamente farei in modo diverso...
>  
>> function recursively_find_text_nodes($dom_element) {
>>   global $node;
>>   $return = array();
>>
>>   foreach ($dom_element->childNodes as $dom_child) {
>>      switch ($dom_child->nodeType) {
>> 	case XML_TEXT_NODE:
>> 	  if (trim($dom_child->nodeValue) !== '') {
>> 			$return[] = $dom_child->nodeValue;
>> 			$node[] = $dom_child;
> 
> Qui i due valori sono strettamente correlati.
> 
> Hai due possibilità, secondo me:
> 
> 1- tornare solo il nodo, che tanto da lì puoi sempre recuperare il valore:
>  $return[] = $domNode;
> 
> 2- tornare ogni elemento come "sotto-array" che li contiene entrambi:
>  $return[] = [$dom_child, $dom_child->nodeValue];

Non so se l'ultima notazione funziona ma si può scrivere come
$return[] = [array($dom_child, $dom_child->nodeValue);

In alcuni casi si può anche scrivere come
$return[$dom_child->nodeValue] = $dom_child

> Questa seconda ti permette di fare
> 
> foreach (recursively_find_text_nodes($dom) as list($elem, value)) { ... }
> 
> (Non mi ricordo da che versione di PHP puoi usare "as list()")

Questa mi avrebbe risparmiato un'istruzione.
> 
>> Può funzionare?
> 
> Se <strike>ti vuoi male</strike> vuoi vivere nel futuro, puoi usare i 
> generatori:
> 
> function find_text_nodes($dom_element)
> {
>   foreach ($dom_element->childNodes as $dom_child) {
>     switch ($dom_child->nodeType) {
>       case XML_TEXT_NODE:
>         if (trim($dom_child->nodeValue) !== '') {
>           yield $dom_child;
>         }
>         break;
>         case XML_ELEMENT_NODE:
>           yield from find_text_nodes($dom_child);
> 	break;
>     }
>   }
> }
> 
> foreach (find_text_nodes($elem) as $node) {
>   ...
> }
> 
> WARNING: codice non testato, scritto di getto, e richiede PHP7. :)
> 
> Questa versione ha il vantaggio che non tiene in memoria la lista di tutti 
> i nodi e del loro contenuto, ma ne genera uno alla volta man mano che li 
> consumi, quindi puoi potenzialmente parsare un HTML il doppio più grosso 
> con la stessa quantità di RAM.

Troppo complicato per me...
-- 
Sandro kensan www.kensan.it & www.qiqi.it geek site
Saluto gli agenti della NSA - Hello NSA - www.nsa.gov

[toc] | [prev] | [next] | [standalone]


#20947

Fromfmassei@gmail.com
Date2016-06-17 17:26 -0700
Message-ID<cf9260d3-bf5b-43c8-9235-868190fe5a3b@googlegroups.com>
In reply to#20944
On Friday, June 17, 2016 at 4:34:14 PM UTC-4, Alessandro Pellizzari wrote:
> Se <strike>ti vuoi male</strike> vuoi vivere nel futuro, puoi usare i 
> generatori:
>

ehehehe! Guarda, ero sicuro che, fin da quando abbiamo parlato di generatori
qui qualche mese fa, ti bruciavano le mani per poterli usarli in qualche
esempio :D

> Questa versione ha il vantaggio che non tiene in memoria la lista di tutti 
> i nodi e del loro contenuto, ma ne genera uno alla volta man mano che li 
> consumi, quindi puoi potenzialmente parsare un HTML il doppio più grosso 
> con la stessa quantità di RAM.
> 

Questo secondo me invece è sbagliato. Dovrei fare delle prove per vedere se
ho ragione, ma sono "confident" al 95% :) Scrivo il perché..

Come prima cosa, iniziamo a dire che nel caso in oggetto il generatore deve
generare tutto, ovvero non ci sono casi in cui si processa solo una parte di
input.
La domanda quindi è, quanto si risparmia in termini d'occupazione di memoria
per l'array temporaneo, che in un caso (dell'OP) deve essere tutto presente in
memoria e nell'altro può essere riciclato durante il processing.

Pensiero 1: in ritorno abbiamo un array dove ogni elemento sono due puntatori
(la stringa e il reference ad un DOMelement, che è un resource): su un 64bit
sono 16byte ad elemento, per (diciamo) 100mila nodi fanno 1.5Mbyte. Come
sappiamo la struttura potrebbe non essere compatta, ma in questo caso l'array
sarebbe memoria contigua, per cui anche considerando gli sprechi e i buchi,
è una quantità comunque troppo irrisoria per farci conti sopra..

Pensiero 2: suppongo stiamo usando il GC (altrimenti non avrebbe nemmeno senso
fare questo discorso..). Calcolare quanta memoria è riciclata durante l'uso
d'un generatore è compito arduo, ma in questo caso si può fare un'osservazione
facile: visto che il GC di PHP opera con reference-counting, e visto che il DOM
rimane referenziato mentre gira il generatore, non è possibile riciclare nulla
di quello che effettivamente pesa! L'unico riciclo sarebbe sul riuso della
struttura di cui sopra (quel megabyte e qualcosa).

Pensiero 3: per quanto riguarda le performances, sia di memoria che di CPU,
ovviamente sia la soluzione dell'OP che i generatori sono una bestemmia :)
La migliore soluzione è, naturalmente, la classica map (che si emula in PHP con
il passaggio di una callback alla funzione che cicla l'albero).

Ciao!

[toc] | [prev] | [next] | [standalone]


#20951

FromAlessandro Pellizzari <shuriken@amiran.it>
Date2016-06-18 16:28 +0000
Message-ID<dslb5aFj5kiU1@mid.individual.net>
In reply to#20947
Il Fri, 17 Jun 2016 17:26:37 -0700, fmassei ha scritto:

> On Friday, June 17, 2016 at 4:34:14 PM UTC-4, Alessandro Pellizzari
> wrote:
>> Se <strike>ti vuoi male</strike> vuoi vivere nel futuro, puoi usare i
>> generatori:

> ehehehe! Guarda, ero sicuro che, fin da quando abbiamo parlato di
> generatori qui qualche mese fa, ti bruciavano le mani per poterli usarli
> in qualche esempio :D

Ah, beccato! :D

In realtà ultimamente "mi tocca" perchè il nostro frontendista sta 
spingendo un po' troppo velocemente react.js e javascript oltre i limiti, 
e si è messo a usare i generatori per le chiamate asincrone.

Siccome in teoria io dovrei poterlo sostituire in caso di ferie o malattie, 
mi tocca addentrarmici. :)

> Pensiero 1: in ritorno abbiamo un array dove ogni elemento sono due
> puntatori (la stringa e il reference ad un DOMelement, che è un
> resource): su un 64bit sono 16byte ad elemento, per (diciamo) 100mila
> nodi fanno 1.5Mbyte. Come sappiamo la struttura potrebbe non essere
> compatta, ma in questo caso l'array sarebbe memoria contigua, per cui
> anche considerando gli sprechi e i buchi,
> è una quantità comunque troppo irrisoria per farci conti sopra..

Questo effettivamente è vero nel caso di PHP7 (richiesto, tra l'altro) 
viste le ottimizzazioni a livello di copy on write e di allocazione di 
memoria degli array che hanno introdotto.

Diciamo che mi sono trovato a dover processare XML di 100 MB e mi sto 
facendo forse un po' troppe pare. :)
 
> Pensiero 3: per quanto riguarda le performances, sia di memoria che di
> CPU, ovviamente sia la soluzione dell'OP che i generatori sono una
> bestemmia :)
> La migliore soluzione è, naturalmente, la classica map (che si emula in
> PHP con il passaggio di una callback alla funzione che cicla l'albero).

La soluzione migliore sarebbe un parser alla XMLReader, ma effettivamente 
per file così piccoli stiamo pettinando il pelo sull'uovo. :P

Bye.

[toc] | [prev] | [next] | [standalone]


#20953

Fromfmassei@gmail.com
Date2016-06-18 12:29 -0700
Message-ID<ad47a8eb-ba73-4309-807f-2d9bc6f57a8e@googlegroups.com>
In reply to#20951
On Saturday, June 18, 2016 at 12:28:28 PM UTC-4, Alessandro Pellizzari wrote:
> Il Fri, 17 Jun 2016 17:26:37 -0700, fmassei ha scritto:
> > La migliore soluzione è, naturalmente, la classica map (che si emula in
> > PHP con il passaggio di una callback alla funzione che cicla l'albero).
> 
> La soluzione migliore sarebbe un parser alla XMLReader, ma effettivamente 
> per file così piccoli stiamo pettinando il pelo sull'uovo. :P
> 

Ah, fossi stato io avrei usato XPath.. una riga e tutti a casa! ;)

Ciao!

[toc] | [prev] | [standalone]


Back to top | Article view | it.comp.www.php


csiph-web