Ссылка на массив PHP по нескольким индексам
Это может быть какой-то странный более длинный ярлык, и, пожалуйста, поправьте меня, если я ошибаюсь в этом процессе...
У меня есть матрица данных, которая выглядит следующим образом:
unique_id | url | other random data...
unique_id | url | other random data...
unique_id | url | other random data...
Я хочу иметь возможность ссылаться на элемент либо по его URL, либо по уникальному_id - есть ли причудливый способ сделать это?
Я полагаю, что мошенническим решением было бы просто сделать два массива, но мне было интересно, есть ли лучший способ.
4 ответа
Попробуйте что-то вроде этого:
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");
Эта техника имеет немного дополнительных накладных расходов из-за создания объекта, но если вы не делаете безумное количество строк, все будет в порядке.