2010-12-10 21 views
4

Cela peut être une sorte de bizarre raccourci plus, et s'il vous plaît me corriger si je me trompe dans ce train de la pensée ...tableau PHP de référence par plusieurs index

J'ai une matrice de données qui ressemble à:

unique_id | url | other random data... 
unique_id | url | other random data... 
unique_id | url | other random data... 

Je veux être en mesure de faire référence à un élément en soit il est URL, ou il est id_unique - est-il un moyen de fantaisie de le faire? Je suppose que la solution de triche serait juste de faire deux tableaux, mais je me demandais s'il y avait une meilleure façon.

+2

Pas vraiment, non. Juste faire deux tableaux. La surcharge est minime (bien, en fonction de la taille de vos tableaux). –

+0

Avez-vous besoin de modifier les "données aléatoires" une fois qu'il est dans le tableau? Et cela est-il possible pour un unique_id et une URL pour entrer en collision? –

+0

Ils devraient toujours être uniques –

Répondre

1

Essayez quelque chose comme ceci:

function selectByIdOrURL($array, $data) { 
    foreach($array as $row) { 
     if($row['unique_id'] == $data || $row['url'] == $data) return $row; 
    } 
    return NULL; 
} 

$array = array(
      array('unique_id' => 5, 'url' => 'http://blah.com'), 
      array('unique_id' => 3, 'url' => 'http://somewhere_else.com') 
     ); 
$found = selectByIdOrURL($array, 5); //array('unique_id' => 5, 'url' => 'http://blah.com') 
$nfound = selectByIdOrURL($array, 10); //NULL 
+0

Est-ce que le seul moyen d'itérer les données? Je suppose que ce n'est pas une affaire énorme, mais je suis vraiment curieux de savoir si vous pouvez avoir plusieurs index pour les tableaux (en général) –

+2

@Bob, non, il n'y a aucun moyen d'avoir plusieurs index pour les tableaux. –

+3

D'une manière générale, non. L'approche la plus rapide (pour les temps d'accès) consiste à avoir deux tableaux, l'un avec l'id unique comme clé, l'autre avec l'URL, et les deux avec toutes les données comme valeur. La réponse de Jacob utilisera légèrement moins de mémoire, mais devra réitérer l'ensemble du tableau chaque fois que vous faites référence à quelque chose; mon approche utilisera un peu plus de mémoire, mais récupérera les résultats plus rapidement. –

9

Seule façon je peux penser cela ne concerne pas itérer le tableau pour chaque recherche (voir la réponse de Jacob) est de stocker des références à chaque élément dans deux tableaux.

Modifier: Comme les URL et les ID ne peuvent pas entrer en collision, ils peuvent être stockés dans le même tableau de référence (merci Matthieu)

$items; // array of item objects 
     // Use objects so they're implicitly passed by ref 

$itemRef = array(); 

foreach ($items as $item) { 
    $itemRef[$item->unique_id] = $item; 
    $itemRef[$item->url] = $item; 
} 

// find by id 
$byId = $itemRef[$id]; 

// find by url 
$byUrl = $itemRef[$url]; 

Vous pourriez probablement résumer cela en utilisant bien une classe de collection qui implémente getById() et getByUrl(). En interne, il pourrait stocker les références dans autant de tableaux que nécessaire.

Bien sûr, ce que vous faites essentiellement ici est de créer des ensembles de résultats indexés, ce qui est préférable aux systèmes de gestion de base de données.

+1

Aussi, vous pouvez les mettre dans le même tableau (par exemple '$ items') si vous choisissez.Il pourrait être légèrement confus, mais Bob a dit que les clés ne peuvent pas entrer en collision. –

+0

@Matthew C'est vrai, je vais modifier ma réponse en conséquence – Phil

+0

Oh c'est intéressant. Ils ne se heurtent pas, mais il semble un peu effrayant d'un point de vue de la vulnérabilité (par exemple une recherche qui a été forcée en utilisant une URL au lieu d'un unique_id). Belle technique cependant –

0

Sûrement un objet serait le moyen facile?

class Item { 
    public $unique_url; 
    public $url; 
    public $other_data; 

    public function __construct($unique_url, $url, $other_data) 
    { 
     $this->unique_url = $unique_url; 
     $this->url = $url; 
     $this->other_data = $other_data; 
    } 
} 



class ItemArray { 
    private $items = array(); 

    public function __construct() 
    { 
    } 

    public function push(Item $item) 
    { 
     array_push($items, $item); //These may need to be reversed 
    } 

    public function getByURL($url) 
    { 
     foreach($items as $item) 
     { 
      if($item->url = $url) 
      { 
       return $item; 
      } 
     } 
    } 

    public function getByUniqueURL($url) 
    { 
     foreach($items as $item) 
     { 
      if($item->unique_url = $unique_url) 
      { 
       return $item; 
      } 
     } 
    } 

} 

utiliser ensuite avec

$itemArray = new ItemArray(); 
$item = new Item("someURL", "someUniqueURL","some other crap"); 
$itemArray->push($item); 

$retrievedItem = $itemArray->getItemByURL("someURL"); 

Cette technique a un peu de frais généraux supplémentaires en raison de création d'objets, mais à moins que vous faites un nombre fou de lignes, il serait bien.

1

Il semble que votre solution de fantaisie n'était disponible qu'à partir de PHP 5.5. Vous pouvez combiner l'utilisation de array_search et array_column chercher votre entrée dans une seule ligne de code:

$items = [ 
    [ 
    'unique_id' => 42, 
    'url' => 'http://foo.com' 
    ], 
    [ 
    'unique_id' => 57, 
    'url' => 'http://bar.com' 
    ], 
    [ 
    'unique_id' => 36, 
    'url' => 'http://example.com' 
    ], 

]; 

$bar = $entries[array_search(57, array_column($items, 'unique_id'))]; 

var_dump($bar); 

//outputs 
array (size=2) 
    'unique_id' => int 57 
    'url' => string 'http://bar.com' (length=14)