PHP: Effettuare una ricerca in Array Multidimensionali

11 Feb 2020 | M.A.D.R.

Parliamo di ricerca in array: questo piccolo snippet sarà un nostro fidato compagno per la ricerca in array multidimensionali in PHP.

Non di rado si trovano, in vari forum e discussioni varie, articoli su come effettuare una ricerca su array multidimensionali.

Se non hai idea di come quest'ultimi funzionino controlla qui (articolo su cosa sono e come si usano gli array), una piccola panoramica sugli array.

Andiamo subito al nocciolo delle questione.

Sappiamo che è possibile effettuare delle ricerche attraverso i classici loop, parliamo del for-while-foreach, e quanto questi costrutti siano assolutamente efficaci e facili da implementare.

Nella loro semplicità, spesso inducono ad errori più o meno comuni, senza far si che il programmatore si renda conto che una porzione di codice non sia ottimizzata e soprattutto richiede molta memoria e tempo.

In pratica??

Affrontiamo subito qualche esempio per capire di cosa si sta parlando. Immaginiamo di avere un set di elementi all'interno dell'array in questo modo:

Array
(
    [0] => Array
        (
            [transactionID] => MqNs
            [tag] => BCwu
            [cast] => SB
            [items] => 62
            [filled] => 4
        )
)

I più smaliziati potrebbero subito affrontare, con molto successo, una ricerca lineare attuando il semplice e sempre utile loop degli elementi (foreach-for-while).

É vero, funziona, ma quanto costa una ricerca in questo modo? e soprattutto quanto devo scrivere prima di riuscire a trovare quello che serve?

Vediamo nel dettaglio un primo esempio di codice che eseue una ricerca solo su un campo definito a priori dal programmatore. Il codice è autoparlante, non mi soffermerò più di tanto:

function ricerca_elementi($array,$ricerca){
	$data_return=[];
	foreach ($array as $k=>$v){
	    if($v['items']==$ricerca)$data_return[]=$v;
	}
	return $data_return;
}

Possiamo subito notare che all'interno del nostro ciclo abbiamo un nuovo costrutto "IF" che permette di effettuare una scelta.

In questo modo è relativamente semplice affrontare un problema del genere, i guai iniziano con il dover cercare più elementi nello stesso array, ossia il parametro ricerca non sarà più testuale ma sarà a sua volta un'array con combinazione chiave=>valore per effettuare la ricerca.

Vediamo il suo codice:

function ricerca_elementi_array($array,$ricerca){
	$data_return=[];
	foreach ($array as $k=>$v){
		$trovato=true;
		foreach ($ricerca as $chiave_ricerca=>$valore_ricerca){
			if($v[$chiave_ricerca]!=$valore_ricerca)$trovato=false;
		}
		if($trovato)$data_return[]=$v;
	}
	return $data_return;
}

Notiamo immediatamente che abbiamo dovuto implementare un nuovo ciclo all'interno, il che seppur funzionale non è ottimizzato.

Abbiamo scritto una banale funzione che consente al programmatore di avere un risultato abbastanza velocemente, a quale costo?

Codice non ottimizzato, di facile lettura ma molto lento sui grandi numeri.

Vediamo invece adesso alcuni esempi su come affrontare questo problema.

In questa prima versione, seppur ottimizzata non è il nostro massimo in termini di performance:

function serach_array_wfilter($array,$filter){
		$t=array_flip($filter);
		$number_t=count($t);
		return array_filter($array, function($current) use ($filter,$t,$number_t){
			return (count(array_intersect_key(array_flip($current),$t))==$number_t);
		});
	}

Cosa abbiamo fatto?

  • Abbiamo invertito le chiavi con i valori dell'array filter
  • Contiamo il numero degli elementi di filter
  • Effettuiamo l'intersezione di $t (flip di $filter) con il flip dell'elemento i-esimo di array

Sicuramente migliore in termini di performance ma abbastanza pesante per il sistema.

Una versione migliorata del codice sopra:

function search_w_intersect_assoc($array,$filter){
		$number_t=count($filter);
		return array_filter($array, function($current) use ($filter,$number_t){
			return(count(array_intersect_assoc($current,$filter)) == $number_t);
		});
	}

Questa è la versione migliorata che fa uso dell'intersezione associativa dei due array.

In termini temporali la prima versione è adatta per un numero limitato di ricerche e su pochi campi degli elementi in filter, quindi seppur non ottimizzata se dovessimo utilizzarla per uso comune non ci sono problemi.

Le altre due si prestano ad un numero maggiore elementi sia nell'array che nel filter riducendo il tempo rispettivamente:

Funct1 = N

Funct2 = N/2

Funct3 = Funct2/3

Quindi la più performante che riduce drasticamente il tempo d'esecuzione è sicuramente la terza, la quale impiega 1/3 rispetto alla seconda che impiega 1/2 della prima....

Niente male per un filtro......
Leggi anche:

Soluzioni complete per ogni esigenza