2009-11-18 5 views
0

J'ai un grand tableau en PHP.Manière rapide d'extraire des portions de tableau?

Il contient des chaînes qui sont divisés en une sorte de catégories en utilisant underscores:

category1_property 
category1_category2_category3 
category2_category3_category4_category5 

J'ai une fonction nommée

array get_values($prefix) 

qui renvoie toutes les valeurs du tableau qui commencent par un préfixe donné , par exemple

get_values("category2_category3_"); 

Cette fonction foreach() es à travers le réseau tout à chaque fois, la collecte de toutes les chaînes qui commencent par le préfixe, soit d'un simple

foreach ($my_array as $line) 
if (substr($line, 0, strlen($prefix)) == $prefix)) 
    array_push ($result, $line); 

Je me sens mal le faire sage performance, surtout en voyant que cette opération est effectuée des dizaines de fois par demande.

Est-ce que quelqu'un connaît un moyen d'accélérer cela sans avoir à recourir à une toute autre façon de stocker les données?

L'utilisation d'une base de données peut être rapide et intelligente, mais je voudrais éviter cela. Les données proviennent d'un fichier et je ne peux pas le porter sur une base de données.

pré-tri ou diviser la construction en un tableau multidimensionnel ou un objet est pas une option, parce que je dois parfois interroger pour les parties d'un nom de catégorie (par exemple « category1_ca * »)

Merci à avancer pour toute entrée.

+0

Comment est-il maintenant rapide et combien voulez-vous accélérer? – intgr

Répondre

1

Pour un accès efficace en temps, je pense que la solution la plus simple consiste à trier la matrice et à utiliser une variante modifiée du binary search algorithm pour trouver les limites de tableau inférieures et supérieures correspondant à votre requête. Cela fonctionne parce que les chaînes avec des préfixes similaires sont toujours triées séquentiellement.

Une fois que vous avez cette plage, l'extraction des éléments correspondants est une simple boucle.

Évidemment ce n'est pas une tâche triviale, alors ne perdez pas de temps à ce sujet à moins que ce vraiment est un problème de performance. L'optimisation prématurée, vous savez l'exercice ...

1

On ne sait pas ce que la fonction get_values ​​devrait correspondre - de toute façon, cela peut être la solution de performance que vous recherchez?

function get_values($prefix) { 
    $included_array_from_file = array ("category1_property", "category1_category2_category3", "category2_category3_category4_category5"); 

    foreach($included_array_from_file as $val) { 
     if(strpos($val,$prefix)===0) { 
      $out[] = $val; 
     } 
    } 
    return $out; 
} 

print_r(get_values("category2_category3_")); 

Sortie:
Array ([0] => category2_category3_category4_category5)

MISE À JOUR:

Vous devez compter combien de fois "category2_category3_" se produisent dans la chaîne, à droite? Dans ce cas, je vous suggère de créer un tableau multidimensionnel pour la chaîne complète et de compter chaque occurrence comme indiqué dans cet exemple: (Veuillez noter que l'exemple illustre uniquement comment cela peut être fait - l'exemple échoue actuellement car je suis Vous ne savez pas comment créer le tableau multi-dimensionnel à la volée, vous devrez peut-être appeler une autre fonction "create array" lors de l'ajout d'éléments au tableau.

Échec ("Impossible d'utiliser une valeur scalaire en tant que matrice") - Je ne suis pas sûr de savoir comment.

$data = array("category1_property", "category1_category2_category3", "category2_category3_category4_category5"); 
$counter = array(); 
foreach($data as $val) { 
    foreach(explode(":",$val) as $val2) { 
     // Now, create a multi-dimensional array with the category items as keys and increment the value by one for each item in the string, as in this example: 
     // "category2_category3_category4_category5" ... turns into: 
     // $counter[category2] += 1; 
     // $counter[category2][category3] += 1; 
     // $counter[category2][category3][category4] += 1; 
     // $counter[category2][category3][category4][category5] += 1; 
    } 
} 

Utilisation prévue:

echo $counter[category2][category3]; 
+0

C'est ce que je fais en ce moment. Je suis préoccupé par le fait que l'appel de get_values ​​() une centaine de fois (avec une centaine de boucles) est lourd de performance. Je ne vais probablement pas faire un tri préalable. –

+0

Pekka, Comment la nouvelle solution proposée fonctionne-t-elle pour vous? –

1

Vous avez vraiment limité les options! Même ainsi, je pense que le pré-découpage des données peut être la voie à suivre. Considérez:

préfixes 'cat1_cat2_cat3_dog'='fido', 'cat1_cat2_cat3_fish'='goldie', 'cat1_cat2_cat3_frog'='kermit devient

$arr[cat1][cat2][cat3][dog]=fido 
$arr[cat1][cat2][cat3][fish]=goldie 
$arr[cat1][cat2][cat3][frog]=kermit 

Si vous voulez que tout le préfixe cat1_cat2:

$arr['cat1']['cat2']=array('cat3'=>array('dog'=>'fido','fish'=>'goldie')); 

Si vous voulez que tout le préfixe cat1_cat2_cat3_f* il vous suffit de rechercher le dernier terme en $arr['cat1']['cat2']['cat3']:

$matches=preg_grep("/^f/",array_keys($arr['cat1']['cat2']['cat3'])); 
foreach($matches as $k){ 
    $results[]=$arr['cat1']['cat2]['cat3'][$k]; 
} 
+0

Je ne vais probablement pas les contourner avant de les scinder. Merci pour la contribution. –

0

Ou vous pouvez utiliser une fonction anonyme avec array_filter():

function get_values($arr, $str) 
{ 
    $func = create_function('$item', 'return (strpos($item, "' . $str . '") === 0);'); 
    return array_filter($arr, $func); 
} 

$prefix = 'category1'; 
$result = get_values($my_array, $prefix); 
+0

Lorsqu'elle est appelée plusieurs fois, cela a le même inconvénient que la fonction que j'utilise actuellement: elle doit invariablement faire une boucle dans tout le tableau. –

+0

Bien sûr, il boucle tout le tableau. Sinon, comment allez-vous vérifier chaque élément dans le tableau? (Puisque vous avez exclu toute autre option, comme «une manière totalement différente de stocker» (par exemple, mettre en cache des résultats, utiliser une base de données, etc.) Cette méthode est rapide, mais je vous concède que ce n'est pas magiquement instantané. – GZipp

Questions connexes