Справочный массив PHP по нескольким индексам

Это может быть какой-то странный длинный ярлык, и, пожалуйста, поправьте меня, если я ошибаюсь в этом процессе мысли …

У меня есть матрица данных, которая выглядит так:

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

Я хочу, чтобы иметь возможность ссылаться на элемент по его URL-адресу, или это уникальный_id – есть ли способ сделать это?

Я предполагаю, что решение обмана будет состоять в том, чтобы просто создать два массива, но мне было интересно, есть ли лучший способ.

Попробуйте что-то вроде этого:

 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 

Единственный способ, которым я могу думать об этом, не включает итерацию массива для каждого поиска (см. Ответ Джейкоба) – хранить ссылки на каждый элемент в двух массивах.

Изменить : поскольку URL-адреса и идентификаторы не могут столкнуться, они могут храниться в одном и том же массиве ссылок (спасибо Мэтью)

 $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]; 

Вы могли бы, вероятно, инкапсулировать это красиво, используя класс коллекции, который реализует getById() и getByUrl() . Внутри он мог хранить ссылки в таком количестве массивов, сколько необходимо.

Конечно, то, что вы здесь делаете, это создание индексированных наборов результатов, что лучше всего подходит для систем управления базами данных.

Похоже, ваше модное решение доступно только с PHP 5.5 . Вы можете комбинировать использование array_search и array_column для извлечения вашей записи в одной строке кода:

 $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) 

Наверняка, объект был бы простым способом?

 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; } } } } 

Затем используйте его с

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

У этого метода есть немного дополнительных накладных расходов из-за создания объекта, но если вы не делаете безумных рядов строк, все будет хорошо.