È una buona idea modificare le chiavi dell'array in foreach

2

Alcune volte ho bisogno di modificare una chiave di array per esempio qualcosa di simile:

$temp = array();
foreach($arrayIWantToModify as $key => $value) {
    if($value % 2) == 0) {
        $temp['odd_' . $key] = $value;
    } else {
        $temp[$key] = $value;
    }
}

Uso sempre un array temporaneo per ottenerlo, ma ho riscontrato un problema di memoria durante il lavoro su un progetto con alcuni array di grandi dimensioni. Ovviamente la soluzione migliore è aumentare la memoria ma, mi stavo solo chiedendo, è così brutto farlo come:

foreach($arrayIWantToModify as $key => $value) {
    if(($value % 2) == 0) {
        $arrayIWantToModify['odd_' . $key] = $value;
        unset($arrayIWantToModify[$key]);
    }
}

Sembra funzionare ma l'ho sempre visto come una cattiva pratica perché stai modificando un array che stai iterando.

    
posta siper92 26.08.2015 - 22:58
fonte

3 risposte

6

Sono d'accordo che questa non è una buona idea. Anche se il linguaggio che stai usando definisce cosa dovrebbe accadere in questa situazione (non so se PHP lo fa, questa è una domanda per StackOverflow) la maggior parte delle persone che vedono un codice come questo dovrebbe ancora cercare se è definito o meno un comportamento prima che potessero avere fiducia in esso.

Se la lista delle modifiche desiderate è tipicamente molto più piccola della matrice che viene modificata, preferirei sempre usare una matrice temporanea per contenere le modifiche desiderate fino a completare l'iterazione, proprio come il primo esempio. Se stai esaurendo la memoria facendo ciò, questo mi dice che stai modificando una porzione così grande della matrice che staresti meglio con un'operazione di mappatura (credo che PHP la chiami array_map ) progettata per funzionare in modo efficiente modifica tutti elementi senza alcun rischio di elaborare un elemento più o meno di una volta.

    
risposta data 26.08.2015 - 23:16
fonte
3

In PHP il ciclo foreach crea una variabile temporanea che memorizza l'array iniziale passato. puoi passare $ valore per riferimento usando il valore & $. Nei due esempi seguenti i loop rimuovono l'elemento successivo nell'array.

Poiché si tratta di una variabile temporanea, le modifiche all'originale non hanno alcun effetto sul ciclo foreach.

<?php 
$arr = array(1,2,3,4,5,6,7,8,9); 

foreach($arr as $key=>$value) 
{ 
    unset($arr[$key + 1]); 
    echo $value . PHP_EOL; 
} 
?> 

Output: 1 2 3 4 5 6 7 8 9

<?php 
$arr = array(1,2,3,4,5,6,7,8,9); 

while (list($key, $value) = each($arr)) 
{ 
    unset($arr[$key + 1]); 
    echo $value . PHP_EOL; 
} 
?> 

Output: 1 3 5 7 9

    
risposta data 31.08.2015 - 12:05
fonte
0

Usiamo un approccio leggermente diverso al problema. Descrivi cosa fai come:

Some times I need to modify an array key

Quando lo guardiamo in questo modo, abbiamo il problema di fare tutto nello stesso ciclo. Possiamo guardarlo in modo diverso? Forse dì:

Some times I need to find a set of keys, and then I need to modify those keys in the array

Ora possiamo vedere due compiti separati da completare, il che significa che possiamo separarli. Il codice per realizzare questo potrebbe sembrare qualcosa di simile:

$oddKeys = array();

// Task 1: Find a set of keys
foreach($arrayIWantToModify as $key => $value) {
    if($value % 2 == 0) {
        $oddKeys[] = $key;
    }
}

// Task 2: Modify those keys
foreach($oddKeys as $key) {
    $arrayIWantToModify['odd_' . $key] = $arrayIWantToModify[$key];
    unset($arrayIWantToModify[$key]);
}

Abbiamo un utilizzo di memoria inferiore * rispetto all'array temporaneo poiché stiamo solo memorizzando le chiavi che devono essere modificate, non un intero array duplicato. Il codice è anche più chiaro dell'alternativa in quanto non vi sono dubbi sul comportamento qui. Poiché abbiamo suddiviso il comportamento, possiamo ora estrarlo e riutilizzarlo altrove (ad esempio estraendo una funzione che restituisce un array di chiavi in cui i valori soddisfano determinati criteri).

* Se il numero di tasti che devono essere cambiati è lo stesso o quasi uguale al numero totale di tasti, i guadagni di utilizzo della memoria potrebbero non essere così grandi. Dovresti testare se stai ancora imbattendo in limiti di memoria, ed eventualmente trovare una strategia diversa (ad esempio, scambia tutte le chiavi, quindi inverti l'azione all'indietro).

    
risposta data 12.10.2015 - 17:41
fonte

Leggi altre domande sui tag