Тот факт, что вы получаете данные из API в формате json, не означает, что вы должны хранить их в заданном формате. Есть несколько стратегий, которые будут более эффективными, чем ваш принятый ответ.
Проблема с текущим выбранным ответом заключается в том, что он будет перебирать полный набор данных каждый раз, когда вы его используете, даже если совпадение найдено на первой итерации. Я не знаю, насколько велик ваш набор данных, но я предполагаю, что он значителен, иначе вы бы не задавали этот вопрос.
Я также не знаю, сколько раз вы хотите получить доступ к набору данных, вы, вероятно, тоже не знаете, но я предполагаю, что этого количества достаточно, чтобы заставить вас задуматься, иначе, опять же, вы бы не задавали этот вопрос.
Предположим, у вас есть набор данных, состоящий из 1000 ваших stdClass
объектов, и вы запрашиваете каждый из этих объектов один раз, поэтому вы обращаетесь к нему 1000 раз.
Теперь предложенный вам метод 'array_filter()' должен обращаться ко всем 1000 элементам (это O(n)) каждый раз, то есть всего 1 000 000 итераций.
//Access every element once using array_filter()
$objectArray = [];
$objectNames = [];
for($i = 0; $i < 1000; $i ++){
$objName = 'object_name_' . ($i + 1);
$objectNames[] = $objName;
$obj = new stdClass();
$obj->name = $objName;
$obj->description = 'test description';
$obj->accessed = 0;
$objectArray[] = $obj;
}
$start = microtime(true);
foreach($objectNames as $name){
$iterations = getObjectWithArray_Filter($name, $objectArray);
}
$end = microtime(true);
$taken = $end - $start;
echo $iterations . " iterations using array_filter() in $taken seconds<br/>\n";
посмотрите, как это работает.
Первая альтернатива, которая приходит на ум, — это старый добрый foreach()
loop, это тоже O(n), но цикл можно записать в залог, как только он найдет совпадение. Таким образом, если мы получим доступ к каждому элементу массива, когда у нас будет 500 500 итераций, экономия составит около 50%. Это может или не может применяться в реальном мире, вы будете лучшим судьей об этом.
//Access every element once using foreach(){}
$objectArray = [];
$objectNames = [];
for($i = 0; $i < 1000; $i ++){
$objName = 'object_name_' . ($i + 1);
$objectNames[] = $objName;
$obj = new stdClass();
$obj->name = $objName;
$obj->description = 'test description';
$obj->accessed = 0;
$objectArray[] = $obj;
}
$start = microtime(true);
foreach($objectNames as $name){
$iterations = getObjectWithForeach($name, $objectArray);
}
$end = microtime(true);
$taken = $end - $start;
echo $iterations . " iterations using foreach(){} in $taken seconds<br/>\n";
посмотрите, как это работает.
Второй вариант, который приходит мне в голову, — это один раз пройтись по массиву и записать его в ассоциативный массив. Первый проход будет O(n), 1000 итераций, и после этого мы сможем получить доступ к нужному элементу напрямую, вообще не проходя через массив, что равно O(1). Давая нам 2000 итераций для доступа к каждому элементу массива один раз.
//Access every element once using Associative array
$objectArray = [];
$objectNames = [];
for($i = 0; $i < 1000; $i ++){
$objName = 'object_name_' . ($i + 1);
$objectNames[] = $objName;
$obj = new stdClass();
$obj->name = $objName;
$obj->description = 'test description';
$obj->accessed = 0;
$objectArray[] = $obj;
}
$associativeArray = [];
$start = microtime(true);
foreach($objectArray as $object){
$associativeArray[$object->name] = $object;
$object->accessed ++;
}
foreach($objectNames as $name){
$iterations = getObjectFromAssociativeArray($objName, $associativeArray);
}
$end = microtime(true);
$taken = $end - $start;
echo $iterations . " iterations using associative array{} in $taken seconds<br/>\n";
посмотрите, как это работает.
Вот остальная часть моего тестового кода: -
//=================================================================
function getObjectWithArray_Filter($objectName, array $objectArray){
$myobjects = array_filter($objectArray, function($e) use($objectName) {
$e->accessed ++;
return strcmp($e->name, $objectName) == 0;
});
$iterations = 0;
foreach($objectArray as $object){
$iterations += $object->accessed;
}
return $iterations;
}
function getObjectWithForeach($objectName, array $objectArray){
$iterations = 0;
$found = false;
$count = 0;
while(!$found){
$objectArray[$count]->accessed ++;
if($objectArray[$count]->name === $objectName){
$found = true;
}
$count ++;
}
foreach($objectArray as $object){
$iterations += $object->accessed;
}
return $iterations;
}
function getObjectFromAssociativeArray($objectName, array $objectArray){
$iterations = 0;
if($objectName === $objectArray[$objectName]->name){
$objectArray[$objectName]->accessed ++;
}
foreach($objectArray as $object){
$iterations += $object->accessed;
}
return $iterations;
}
tl;dr
Вывод на 3v4l.org: –
Accessing 1000 elements once took 1000000 iterations using array_filter() in 0.5374710559845 seconds
Accessing 1000 elements once took 500500 iterations using foreach(){} in 0.2077169418335 seconds
Accessing 1000 elements once took 2000 iterations using associative array{} in 0.1438410282135 seconds
посмотрите, как это работает.
Разница во времени тоже интересна. Вам может понадобиться или не потребоваться оптимизация для такой скорости, но я бы предположил, что это полезное изменение для вашего кода. В любом случае я думаю, что отсутствие итераций после первой намного лучше, чем 1000 или в среднем 500,5 каждый раз.
Я надеюсь, что вы сочтете это полезным упражнением, ваш вопрос пробудил во мне интерес, и я был убежден, что принятый вами ответ был не лучшим решением для вас. Вы можете все еще думать, что это так, но я предлагаю это как альтернативу.
Самый простой способ реализовать это - использовать какое-то хранилище/фабрику объектов: -
class ObjectStore
{
private $decoded;
private $asssocArray;
public function __construct($jsonEncodedObjects)
{
$this->decoded = json_decode($jsonEncodedObjects);
}
public function getObject($objectName)
{
if(!$this->asssocArray){
foreach($this->decoded as $object){
$this->asssocArray[$object->name] = $object;
}
}
return $this->asssocArray[$objectName];
}
}
Таким образом, ваш первый запрос на объект будет O(n), а последующие запросы будут O(1).
Чтобы использовать это с вашим кодом: -
$objectStore = new ObjectStore(getJsonEncodedData());
$hashtag = "test-song-poll-03";
$myObject = $objectStore->getObject($hashtag);
person
vascowhite
schedule
05.05.2014