2010-07-25 3 views
0

J'ai un tableau avec une série d'ID d'événement organisés comme suit: $ event ['year'] ['month'] ['day'] = $ event_id (structure complète ci-dessous).PHP Retour Section d'un tableau multidimensionnel

Fondamentalement, je veux sortir les 5 prochains événements (ou plus) d'une date donnée (comme aujourd'hui).

J'ai passé en revue le manuel PHP, mais je n'ai pas trouvé de solution appropriée. Je suppose que je pourrais juste parcourir chaque étape, mais il pourrait y avoir des centaines d'événements. Si je connaissais le décalage, je pourrais utiliser array_slice, mais je ne suis pas sûr de savoir comment obtenir le décalage sans boucler tout le tableau. Si je pouvais définir le pointeur, alors je passerais juste à travers. Mais je comprends qu'il n'y a pas moyen de définir un pointeur dans un tableau PHP.

Une requête MySQL spécifique n'est pas très faisable non plus puisque les données ne sont pas bien organisées (c'est l'utilisation de clés méta dans une base de données Wordpress). Je devrais probablement utiliser un certain nombre de JOINs, donc je pense que le coup de performance serait mauvais.

Compte tenu de l'année en cours, le mois et le jour (par exemple $ événement [année $] [mois $] [$ jour], je veux juste montrer les 5 prochains événements.

La structure ressemble à ceci :

Array 
(
    [2010] => Array 
     (
      [1] => Array 
       (
        [1] => Array 
         (
          [594] => "Event" 
         ) 
       ) 
      [2] => Array 
       (
        [1] => Array 
         (
          [592] => "Event", 
          [524] => "Event" 
         ) 

        [2] => Array 
         (
          [580] => "Event" 
         ) 
    [2011] => Array 
     (
      [1] => Array 
       (
        [1] => Array 
         (
          [587] => "Event" 
         ) 
       ) 
     ) 
) 

pensées Désolé si cette description est un peu compliqué Merci

Edit:?.! Typos

Répondre

0

Ce ne sera pas rapide, car il parcourt l'ensemble de la baie. En fait, c'est probablement une mauvaise façon de le faire. Malheureusement, cela pourrait être le moyen le plus simple. La date réelle de chaque événement n'est pas stockée directement, mais nous pouvons la dériver.

$earliest_date = strtotime('next Monday'); // or whatever. 
$new_events = array(); 
foreach($array as $year => $a) { 
    foreach($array[$year] as $month => $b { 
     foreach($array[$year][$month] as $day => $events) { 
      $date = strtotime("$year-$month-$day"); 
      if($date >= $earliest_date) 
       $new_events[] = array('date' => $date, 'events' => $events); 
      if(count($new_events) >= 5) 
       break 3; // Breaks out of all three loops. 
     } 
    } 
} 

à noter, le nouveau tableau choisit les cinq événements à compter de la date, mais parce qu'il peut y avoir plusieurs événements par jour (par vos données de l'échantillon), il est possible que seulement quelques-uns des événements peut être le tableau.

+0

Charles, merci pour la réponse! Oui, c'est ce que je pensais faire. Malheureusement, je crains qu'une telle méthode ait un impact sur les performances du site (cela s'affichera sur la page d'accueil). Peut-être que la solution consiste à faire cela et à mettre en cache le résultat. – Darren

+0

Pouvez-vous nous en dire plus sur ce qui génère le tableau dans ce format? Idéalement, votre meilleure solution limiterait la plage de dates qui va dans le tableau pour commencer. – Charles

+0

Bien sûr, le code est ici: http://pastebin.com/YhpXWaAK J'ai pensé à simplement ajouter un if/then pour vérifier si la date donnée est antérieure à la date de l'événement et la filtrer. Cependant, cela nécessite encore une boucle à travers tous les événements de la base de données (pire, je pense, car cela a beaucoup de requêtes de base de données). Ce site n'obtient pas d'énormes quantités de trafic (il s'agit d'un site intranet), donc peut-être que l'impact sur les performances des boucles foreach imbriquées dans votre exemple de code ne sera pas si grave? – Darren

0

Si l'arr ay est ordonné, vous pouvez utiliser binary search pour trouver la date d'aujourd'hui ou la chose la plus proche avant aujourd'hui (s'il n'y a pas d'entrées pour aujourd'hui). Puis, vous devrez parcourir le tableau comme s'il était plat et sortir les trois entrées suivantes.

Cela vaut mieux que d'itérer sur l'ensemble de la baie car elle ne prend pas de temps linéaire.

+0

Artefacto, merci pour l'aide! Je devais lire l'article de Wikipédia pour savoir de quoi tu parlais. Utile à savoir. Dans ce cas, la fonction connaîtra toujours la date du jour (ou quelle que soit la date de début donnée). Le problème est l'itération à travers le tableau multidimensionnel pour les 5 événements après la date connue. J'essaie d'éviter une boucle itérative intensive dans le tableau (comme celle de Charles). – Darren

+0

@dkrape Ah, je vois maintenant le problème. Vous ne pouvez pas vraiment naviguer dans le tableau car vous ne connaissez pas le nom de l'entrée suivante. Il n'y a vraiment aucun moyen de le faire sans parcourir tout le tableau, car PHP n'expose malheureusement pas un moyen de définir le pointeur interne sur un élément spécifique afin que vous puissiez utiliser 'next' et' prev'. – Artefacto

+0

Ah, bon à savoir.Je jouais avec next() et prev(), mais je continuais à devoir revenir à un niveau plus élevé du tableau (par exemple, commencer à jour, puis revenir au mois, puis revenir à l'année). À la fin, je faisais simplement une boucle dans le complet d'une manière plus compliquée. – Darren

0

Certains optimisation pour cette solution:

$earliest_date = strtotime('next Monday'); // or whatever. 

$earliest_year = date('Y', $earliest_date); 

$earliest_month = (int)date('m', $earliest_date); //(int) for leading zero remove 

$earliest_day = date('j', $earliest_date); $new_events = array(); 

foreach($array as $year => $a) { 
    if ($year>=$earliest_year) { 
     foreach($array[$year] as $month => $b { 
      if ($month>=$earliest_month) { 
       foreach($array[$year][$month] as $day => $events) { 
        $date = strtotime("$year-$month-$day"); 
        if($date >= $earliest_date) { 
         $new_events[] = array('date' => $date, 'events' => $events); 
         if(count($new_events) >= 5) { 
          break 3; // Breaks out of all three loops. 
         } 
        } 
       } 
      } 
     } 
    } 
}