PHP - Вилучення властивості з масиву об'єктів


128

У мене є масив об'єктів котів:

$cats = Array
    (
        [0] => stdClass Object
            (
                [id] => 15
            ),
        [1] => stdClass Object
            (
                [id] => 18
            ),
        [2] => stdClass Object
            (
                [id] => 23
            )
)

і я хочу витягнути масив ідентифікаторів котів в 1 рядок (не функція, ні цикл).

Я думав про використання array_walkз , create_functionале я не знаю , як це зробити.

Будь-яка ідея?


Я не хочу використовувати цикл, тому що я хочу мати можливість призначити результат в 1 рядку: $ cats_id = myfunction ($ cats); / * має повернути Array (15, 18, 23) * /
abernier

Відповіді:


150

Якщо у вас PHP 5.5 або новішої версії , найкращим способом є використання вбудованої функції array_column():

$idCats = array_column($cats, 'id');

Але син повинен бути масивом або перетвореним на масив


12
Це насправді найкраща відповідь
Дмитро Буслаєв

1
Найкраще рішення, але доступне лише для php 5.5 і вище
Ludo - Вимкнено запис

2
ніхто так і не повинен кодувати більше 5.5. 3.5-річна версія мови програмування ...
Toskan

11
Це рішення не дає відповіді на питання , тому що, array_columnне працює з arrayпро objectз на всіх. Оскільки PHP 7.0.0 можливий: stackoverflow.com/a/23335938/655224
алгоритм

1
Він працює лише тоді, коли власність об’єкта має загальнодоступний доступ.
Кароль Гасієніка

154

Попередження create_function() знято з PHP 7.2.0. Покладатися на цю функцію дуже не рекомендується.

Ви можете використовувати array_map()функцію.
Це слід зробити:

$catIds = array_map(create_function('$o', 'return $o->id;'), $objects);

54
це правильне рішення і призведе до того, що кожен майстер, що надається, буде "wtf" 'd: D
Андреас Клінгер

4
Єдине, що мені не подобається в цьому рішенні - це використання create_function.
Ionuț G. Stan

4
Ви можете використовувати функцію лямбда, але не багато людей працюватимуть PHP 5.3
Грег,

26
Ось ми йдемо: $project_names = array_map(function($project) { return $project->name ;}, $projects );Однак, в цій публікації блогу зазначається, що це може бути в 2,5 рази повільніше / інтенсивніше пам'ять.
Випускний

7
Я дізнався, що щоразу, коли функція створюється з create_functionпам'яттю, зростає. Якщо ви пишете програму з нескінченними петлями і називати array_mapз create_functionв ній ви завжди отримаєте десь Out of memory...то помилку. Тому не використовуйте create_functionта не використовуйтеarray_map(function($o) { return $o->id; }, $objects);
алгоритм

87

Рішення залежить від версії PHP, яку ви використовуєте. Принаймні, є 2 рішення:

По-перше (новіші версії PHP)

Як сказала @JosepAlsina, найкращим, а також найкоротшим рішенням є використання array_columnнаступного:

$catIds = array_column($objects, 'id');

Примітка. Для ітерації arrayвмісту \stdClasses, що використовується у питанні, це можливо лише у версіях PHP >= 7.0. Але при використанні arrayмістять arrays ви можете зробити те ж саме з PHP >= 5.5.

Другий (Старіші версії PHP)

@Greg сказав, що в старих версіях PHP можна зробити наступне:

$catIds = array_map(create_function('$o', 'return $o->id;'), $objects);

Але будьте обережні: у нових версіях PHP >= 5.3.0краще використовувати Closures, як слід:

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

// the output
4235616
4236600
4237560
4238520
...

ДОБРО

while (true)
{
    $objects = array_map(function($o) { return $o->id; }, $objects);

    echo memory_get_usage() . "\n";

    sleep(1);
}

// the output
4235136
4235168
4235168
4235168
...


Це також може бути обговорено тут

Витік пам'яті ?! Чи правильно працює колектор сміття під час використання 'create_function' в межах 'array_map'?


хоча я використовую php 7.2, але здається, що рішення не буде працювати, якщо ви використовуєте об'єкти класу простору імен, і повертає порожній масив.
Мухаммед Омер Аслам

Чи можете ви розмістити подвиг? Короткий фрагмент, щоб краще зрозуміти ваш контекст?
алгоритм

наприклад, побачити цей фрагмент коду , де у мене є список об'єктів моделі , що повертається раздаточная API SDK і коли ми намагаємося використовувати array_columnна цьому масиві він завжди повертає порожній , тоді як ЕТА сниппет працює правильно, обидва мають захищене властивість , яке доступне в другому фрагменті тільки. Я не міг знайти іншої причини, крім простору імен.
Мухаммед Омер Аслам

Коли я пишу objectу своєму рішенні, я маю на увазі objectне «ан» Object. Нижній регістр objectописує простий об'єкт \stdClass. Можливо, в цьому і проблема. У вас Objectє toArrayметод? Використовуй це. Простий objectі arrayмайже такий же. Після інваріант повинен бути дійсним: ((object)(array)$o) === $o. Впроваджуючи __getметод, ви зробите властивості свого класу доступними для всіх. Це може бути очікувана поведінка. Але ви також можете переглядати, array<Object>наприклад, за допомогою array_mapта дзвонити toArray(якщо є), і тоді він також працює
алгоритм

другий фрагмент, який я надав, - це з php, net і використовує той самий об’єкт Class, що і в першому фрагменті, можливо, ви маєте рацію.
Мухаммед Омер Аслам

4
function extract_ids($cats){
    $res = array();
    foreach($cats as $k=>$v) {
        $res[]= $v->id;
    }
    return $res
}

і використовувати його в одному рядку :

$ids = extract_ids($cats);

1
Дякую SilentGhost, але моє питання про те, щоб отримати $ res лише за 1 команду, не використовуючи цикл ...
abernier

2
Яка різниця? Це приблизно так само прямо, як це стає. Напевно, ви будете використовувати більше рядків, використовуючи щось подібне array_walk.
деге

@deceze, елегантне, просте і коротке рішення просто виглядає краще - особливо для чогось такого зрозумілого, як ця операція (наприклад, це не власна логіка, яка займає багато місця та коментарів). Для мене це має велике значення.
Charlie Dalsass

3

КОД

<?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)
}

Я знаю його за допомогою циклу, але це найпростіший спосіб зробити це! І за допомогою функції вона все-таки закінчується в одному рядку.


Я не розумію, чому люди не обирають просто подібні рішення. Здається, логічно зробити це саме так, якщо ви запитаєте мене.
Том Дайер

3

Ви можете легко зробити це з смаколиками узо

$result = array_map(Functions::extract()->id, $arr);

або з масивами (від узо смаколики)

$result = Arrays::map($arr, Functions::extract()->id);

Перевірте: http://ouzo.readthedocs.org/en/latest/utils/functions.html#extract

Дивіться також функціональне програмування з узо (я не можу розміщувати посилання).


3

Попередження create_function() знято з PHP 7.2.0. Покладатися на цю функцію дуже не рекомендується.

Вбудовані петлі в PHP швидше, ніж інтерпретовані петлі, тому насправді має сенс зробити цю однолінійку:

$result = array();
array_walk($cats, create_function('$value, $key, &$result', '$result[] = $value->id;'), $result)


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


0

create_function()Функція застарілим PHP v7.2.0 . Ви можете використовувати array_map()як надано,

function getObjectID($obj){
    return $obj->id;
}

$IDs = array_map('getObjectID' , $array_of_object);

Крім того, ви можете використовувати array_column()функцію, яка повертає значення з одного стовпця вхідного сигналу, ідентифікованого ключем column_key. Необов'язково, може бути наданий індекс_ ключ для індексації значень у поверненому масиві значеннями з стовпця index_key вхідного масиву. Ви можете використовувати array_column, як задано,

$IDs = array_column($array_of_object , 'id');
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.