У меня есть массив объектов кошек:
$cats = Array ( [0] => stdClass Object ( [id] => 15 ), [1] => stdClass Object ( [id] => 18 ), [2] => stdClass Object ( [id] => 23 ) )
и я хочу извлечь массив идентификаторов кошек в 1 строку (а не функцию или цикл).
Я думал об использовании array_walk
с create_function
но я не знаю, как это сделать.
Есть идеи?
Вы можете использовать array_map()
.
Это должно сделать это:
$catIds = array_map(create_function('$o', 'return $o->id;'), $objects);
Если у вас есть PHP 5.5 или новее , лучший способ – использовать встроенную функцию array_column()
:
$idCats = array_column($cats, 'id');
Но сын должен быть массивом или преобразован в массив
Решение зависит от используемой вами версии PHP. По крайней мере, есть два решения:
Как сказал @JosepAlsina, прежде всего лучшее, а также кратчайшее решение – использовать array_column
следующим образом:
$catIds = array_column($objects, 'id');
Примечание. Для итерации array
содержащего \stdClass
es, как используется в вопросе, возможно только с версиями PHP >= 7.0
. Но при использовании array
содержащего array
s, вы можете сделать то же самое с PHP >= 5.5
.
@Greg сказал в более ранних версиях PHP, можно сделать следующее:
$catIds = array_map(create_function('$o', 'return $o->id;'), $objects);
Но будьте осторожны: в новых версиях PHP >= 5.3.0
лучше использовать Closure
s, например:
$catIds = array_map(function($o) { return $o->id; }, $objects);
Первое решение создает новую функцию и помещает ее в вашу оперативную память. По какой-то причине сборщик мусора не удаляет уже созданный и уже вызванный экземпляр функции из памяти. И в следующий раз, когда вызывается этот код, эта же функция будет создана снова. Такое поведение медленно заполняет вашу память …
Оба примера с выходом памяти для их сравнения:
while (true) { $objects = array_map(create_function('$o', 'return $o->id;'), $objects); echo memory_get_usage() . "\n"; sleep(1); } 4235616 4236600 4237560 4238520 ...
while (true) { $objects = array_map(function($o) { return $o->id; }, $objects); echo memory_get_usage() . "\n"; sleep(1); } 4235136 4235168 4235168 4235168 ...
Утечка памяти?! Правильно ли сборщик мусора, используя 'create_function' в 'array_map'?
function extract_ids($cats){ $res = array(); foreach($cats as $k=>$v) { $res[]= $v->id; } return $res }
и использовать его в одной строке :
$ids = extract_ids($cats);
Вы можете сделать это легко с uuzo goodies
$result = array_map(Functions::extract()->id, $arr);
или с массивами (из узе-лайтов)
$result = Arrays::map($arr, Functions::extract()->id);
Выезд: http://ouzo.readthedocs.org/ru/latest/utils/functions.html#extract
См. Также функциональное программирование с ouzo (я не могу опубликовать ссылку).
Встроенные петли в PHP быстрее интерпретируют циклы, поэтому на самом деле имеет смысл сделать это однострочным:
$result = array(); array_walk($cats, create_function('$value, $key, &$result', '$result[] = $value->id;'), $result)
КОД
<?php # setup test array. $cats = array(); $cats[] = (object) array('id' => 15); $cats[] = (object) array('id' => 18); $cats[] = (object) array('id' => 23); function extract_ids($array = array()) { $ids = array(); foreach ($array as $object) { $ids[] = $object->id; } return $ids; } $cat_ids = extract_ids($cats); var_dump($cats); var_dump($cat_ids); ?>
ВЫВОД
# var_dump($cats); array(3) { [0]=> object(stdClass)#1 (1) { ["id"]=> int(15) } [1]=> object(stdClass)#2 (1) { ["id"]=> int(18) } [2]=> object(stdClass)#3 (1) { ["id"]=> int(23) } } # var_dump($cat_ids); array(3) { [0]=> int(15) [1]=> int(18) [2]=> int(23) }
Я знаю, что он использует цикл, но это самый простой способ сделать это! И используя функцию, она все же заканчивается на одной строке.
$object = new stdClass(); $object->id = 1; $object2 = new stdClass(); $object2->id = 2; $objects = [ $object, $object2 ]; $ids = array_map(function ($object) { /** @var YourEntity $object */ return $object->id; // Or even if you have public methods // return $object->getId() }, $objects);
Выход : [1, 2]