2010-06-05 3 views
3

Je suis actuellement une application de l'optimisation de PHP et a trouvé une fonction appelée autour 10-20K fois, donc je pensais que je commencerais là optimisation:clés Conversion d'un tableau/objet arbre en minuscules

function keysToLower($obj) 
{ 
     if(!is_object($obj) && !is_array($obj)) return $obj; 
     foreach($obj as $key=>$element) 
     { 
       $element=keysToLower($element); 
       if(is_object($obj)) 
       { 
         $obj->{strtolower($key)}=$element; 
         if(!ctype_lower($key)) unset($obj->{$key}); 
       } 
       else if(is_array($obj) && ctype_upper($key)) 
       { 
         $obj[strtolower($key)]=$element; 
         unset($obj[$key]); 
       } 
     } 
     return $obj; 
} 

La plupart du temps est passé en appels récursifs (qui sont assez lents en PHP), mais je ne vois aucun moyen de le convertir en boucle. Que feriez-vous?

Cette version ne tient pas compte des tableaux associatifs car mes données n'en ont pas, mais est presque 10 fois plus rapide que la version originale. La majeure partie du travail a été faite par Gumbo, l'accélération majeure vient de l'utilisation de références et de la création d'un nouvel objet au lieu de désactiver les anciennes clés.

function &keysToLower(&$obj) 
{ 
    if(is_object($obj)) 
    { 
     $newobj = (object) array(); 
     foreach ($obj as $key => &$val) 
      $newobj->{strtolower($key)} = keysToLower($val); 
     $obj=$newobj; 
    } 
    else if(is_array($obj)) 
     foreach($obj as &$value) 
      keysToLower($value); 
    return $obj; 
} 
+0

Vous pouvez toujours supprimer facilement les appels récursifs à l'aide d'une pile auxiliaire. – Artefacto

+0

J'ai suggéré array_walk_recursive mais supprimé mon post - Je ne pouvais pas facilement le faire faire ce que vous vouliez, même si vous voudrez peut-être vous pencher sur cette fonction vous-même. – Erik

+0

Apparemment, array_walk_recursive ne considérera pas les éléments créés avec la fonction de rappel. – tstenner

Répondre

4

Foreach utilise une copie interne qui est ensuite traversée. Essayez sans:

function keysToLower($obj) 
{ 
    $type = (int) is_object($obj) - (int) is_array($obj); 
    if ($type === 0) return $obj; 
    reset($obj); 
    while (($key = key($obj)) !== null) 
    { 
     $element = keysToLower(current($obj)); 
     switch ($type) 
     { 
     case 1: 
      if (!is_int($key) && $key !== ($keyLowercase = strtolower($key))) 
      { 
       unset($obj->{$key}); 
       $key = $keyLowercase; 
      } 
      $obj->{$key} = $element; 
      break; 
     case -1: 
      if (!is_int($key) && $key !== ($keyLowercase = strtolower($key))) 
      { 
       unset($obj[$key]); 
       $key = $keyLowercase; 
      } 
      $obj[$key] = $element; 
      break; 
     } 
     next($obj); 
    } 
    return $obj; 
} 

Ou utiliser des références pour éviter qu'une copie est utilisée:

function &keysToLower(&$obj) 
{ 
    $type = (int) is_object($obj) - (int) is_array($obj); 
    if ($type === 0) return $obj; 
    foreach ($obj as $key => &$val) 
    { 
     $element = keysToLower($val); 
     switch ($type) 
     { 
     case 1: 
      if (!is_int($key) && $key !== ($keyLowercase = strtolower($key))) 
      { 
       unset($obj->{$key}); 
       $key = $keyLowercase; 
      } 
      $obj->{$key} = $element; 
      break; 
     case -1: 
      if (!is_int($key) && $key !== ($keyLowercase = strtolower($key))) 
      { 
       unset($obj[$key]); 
       $key = $keyLowercase; 
      } 
      $obj[$key] = $element; 
      break; 
     } 
    } 
    return $obj; 
} 
+0

Fonctionne correctement, sauf avec les tableaux imbriqués sans clé, chaque tableau du second niveau est vide, par ex. 'keysToLower (array (array (array (1,2))))' renvoie 'array (0 => array())' – tstenner

+0

Et le 'if ($ key! == $ keyLowercase)' empêche les valeurs dans un tableau avec une clé minuscule d'être traitée, par exemple 'array ('lowercase' => array ('UPPERCASE' => 1))' ne fonctionnera pas. L'insertion d'un 'else $ val = keysToLower ($ val); – tstenner

+0

Le problème avec les tableaux vides peut être résolu en changeant 'if ($ key! == $ keyLowercase)' à 'if ($ key! == $ keyLowercase &&! Ctype_digit ($ keyLowercase)'. – tstenner

1
array_combine(array_map("strtolower", array_keys($a)), array_values($a)) 
+1

Ne se répète pas, mais probablement un bon début pour accélérer son code – Erik

+0

Fonctionne avec des tableaux, mais ne fonctionne pas avec des objets. – tstenner

+1

Correction: fonctionne avec les tableaux, tant que vous les lancez en utilisant '(tableau) $ a' – tstenner

2

Je suppose que vous ne se soucient pas de la coulée à la matrice ...

function keys_to_lower($o) { 
    if (is_object($o)) { 
     $o = (array)$o; 
    } 
    if (is_array($o)) { 
     return array_map('keys_to_lower', array_change_key_case($o)); 
    } 
    else { 
     return $o; 
    } 
} 
+0

Je m'en soucie, mais je vais mesurer, que ce soit le faire et le refaire avant de revenir sera – tstenner

2

ici un exemple en utilisant lambda:

$multiArrayChangeKeyCase = function (&$array) use (&$multiArrayChangeKeyCase) { 
    $array = array_change_key_case($array); 

    foreach ($array as $key => $row) 
     if (is_array($row)) 
      $multiArrayChangeKeyCase($array[$key]); 
}; 
Questions connexes