PHP - Mengekstrak properti dari larik objek

128

Saya punya berbagai objek kucing:

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

dan saya ingin mengekstrak array ID kucing dalam 1 baris (bukan fungsi atau loop).

Saya sedang berpikir untuk menggunakan array_walkwith create_functiontapi saya tidak tahu bagaimana melakukannya.

Ada ide?

abernier
sumber
Saya tidak ingin menggunakan loop karena saya ingin dapat menetapkan hasil dalam 1 baris: $ kucing_id = fungsi saya ($ kucing); / * harus mengembalikan Array (15, 18, 23) * /
abernier

Jawaban:

150

Jika Anda memiliki PHP 5.5 atau yang lebih baru , cara terbaik adalah menggunakan fungsi bawaan array_column():

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

Tetapi putranya harus berupa array atau diubah menjadi array

Josep Alsina
sumber
12
Ini sebenarnya adalah jawaban terbaik
Dmitry Buslaev
1
Solusi terbaik, tetapi hanya tersedia untuk php 5.5 dan lebih tinggi
Ludo - Tidak dicatat
2
tidak ada yang harus mengkodekan lagi dengan 5.5. Versi bahasa pemrograman 3,5 tahun ...
Toskan
11
Solusi ini tidak menjawab pertanyaan karena, array_columntidak bekerja dengan arraydari objects sama sekali. Karena PHP 7.0.0 dimungkinkan: stackoverflow.com/a/23335938/655224
algoritme
1
Ini hanya berfungsi jika properti objek memiliki akses publik.
Karol Gasienica
154

Peringatan create_function() telah DIHENTIKAN pada PHP 7.2.0. Mengandalkan fungsi ini sangat tidak disarankan.

Anda bisa menggunakan array_map()fungsinya.
Ini harus melakukannya:

$catIds = array_map(create_function('$o', 'return $o->id;'), $objects);
Greg
sumber
54
ini adalah solusi yang tepat dan akan mengarah pada fakta bahwa setiap pengelola yang akan datang akan menjadi "wtf" d: D
Andreas Klinger
4
Satu-satunya hal yang saya tidak suka tentang solusi ini adalah penggunaan create_function.
Ionuț G. Stan
4
Anda dapat menggunakan fungsi lambda tetapi tidak banyak orang yang akan menjalankan PHP 5.3
Greg
26
Ini dia: $project_names = array_map(function($project) { return $project->name ;}, $projects );Namun, dicatat dalam posting blog ini bahwa cara ini bisa menjadi 2,5 kali lebih lambat / intensif memori.
Relequestual
7
Saya menemukan, bahwa setiap kali fungsi dibuat dengan create_functionmemori tumbuh. Jika Anda menulis program dengan loop tak terbatas dan memanggil array_mapdengan create_functiondi dalamnya, Anda akan selalu mendapatkan Out of memory...kesalahan kapan saja. Jadi jangan gunakan create_functiondan gunakanarray_map(function($o) { return $o->id; }, $objects);
algoritme
87

Solusinya tergantung pada versi PHP yang Anda gunakan. Setidaknya ada 2 solusi:

Pertama (Versi PHP yang lebih baru)

Seperti yang dikatakan @JosepAlsina sebelumnya, solusi terbaik dan terpendek adalah menggunakan array_columnsebagai berikut:

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

Perhatian: Untuk iterasi es yang arraymengandung \stdClassseperti yang digunakan dalam pertanyaan itu hanya mungkin dengan versi PHP >= 7.0. Tetapi ketika menggunakan yang arraymengandung arrayAnda dapat melakukan hal yang sama sejak PHP >= 5.5.

Kedua (Versi PHP yang lebih lama)

@Greg mengatakan dalam versi PHP yang lebih lama dimungkinkan untuk melakukan hal berikut:

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

Namun berhati-hatilah: Dalam versi PHP yang lebih baru >= 5.3.0, lebih baik menggunakan Closures, seperti berikut:

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


Perbedaan

Solusi pertama membuat fungsi baru dan memasukkannya ke dalam RAM Anda. Pengumpul sampah tidak menghapus instance fungsi yang sudah dibuat dan sudah dipanggil dari memori karena beberapa alasan. Dan terlepas dari faktanya, bahwa instance fungsi yang dibuat tidak akan pernah bisa dipanggil lagi, karena kita tidak memiliki pointer untuk itu. Dan saat kode ini dipanggil, fungsi yang sama akan dibuat lagi. Perilaku ini perlahan mengisi ingatan Anda ...

Kedua contoh dengan keluaran memori untuk membandingkannya:

BURUK

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
...

BAIK

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

    echo memory_get_usage() . "\n";

    sleep(1);
}

// the output
4235136
4235168
4235168
4235168
...


Ini juga dapat didiskusikan di sini

Kebocoran memori ?! Apakah Pengumpul Sampah melakukan dengan benar saat menggunakan 'create_function' dalam 'array_map'?

algoritme
sumber
meskipun saya menggunakan php 7.2 tetapi sepertinya solusi tidak akan berfungsi jika Anda menggunakan objek kelas namespace, dan mengembalikan array kosong.
Muhammad Omer Aslam
Bisakah Anda memposting eksploitasi? Potongan singkat untuk memahami konteks Anda dengan lebih baik?
Algoritme
misalnya, lihat cuplikan ini di mana saya memiliki daftar objek model yang dikembalikan oleh dropbox API SDK dan ketika kami mencoba untuk menggunakan array_columnpada larik ini, ia selalu mengembalikan kosong sedangkan cuplikan INI berfungsi dengan benar, keduanya memiliki properti terlindungi yang dapat diakses di cuplikan kedua hanya. Saya tidak bisa menemukan alasan lain selain namespace.
Muhammad Omer Aslam
Ketika saya menulis objectdalam solusi saya, maksud saya objectbukan Object. Huruf kecil objectmenggambarkan objek sederhana \stdClass. Mungkin itu masalahnya. Apakah Anda Objectpunya toArraymetode? Gunakan ini. Sederhana objectdan arrayhampir sama. Berikut invarian harus valid: ((object)(array)$o) === $o. Saat menerapkan __getmetode, Anda akan membuat properti kelas Anda dapat diakses oleh semua orang. Ini bisa menjadi perilaku yang diharapkan. Tetapi Anda juga dapat mengulangi array<Object>mis Anda dengan array_mapdan menelepon toArray(jika ada) dan kemudian TI juga berfungsi
algoritme
potongan kedua yang saya berikan adalah dari php, net dan menggunakan objek Kelas yang sama seperti pada potongan pertama, mungkin Anda benar mungkin itu sesuatu yang lain saya akan mencoba dengan mengubahnya menjadi array terima kasih.
Muhammad Omer Aslam
4
function extract_ids($cats){
    $res = array();
    foreach($cats as $k=>$v) {
        $res[]= $v->id;
    }
    return $res
}

dan gunakan dalam satu baris :

$ids = extract_ids($cats);
SilentGhost
sumber
1
Terima kasih SilentGhost, tetapi pertanyaan saya adalah mendapatkan $ res hanya dalam 1 perintah, tidak menggunakan loop ...
abernier
2
Apa bedanya? Ini sesederhana mungkin. Anda mungkin akan menggunakan lebih banyak baris menggunakan sesuatu seperti array_walk.
menipu
@deceze, solusi yang elegan, sederhana, dan singkat terlihat lebih baik - terutama untuk sesuatu yang dapat dijelaskan seperti operasi ini (misalnya, ini bukan logika khusus yang membutuhkan banyak ruang dan komentar). Bagi saya, itu membuat perbedaan besar.
Charlie Dalsass
3

KODE

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

?>

KELUARAN

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

Saya tahu ini menggunakan loop, tetapi ini cara termudah untuk melakukannya! Dan menggunakan fungsi itu masih berakhir pada satu baris.

Luke Antins
sumber
Saya tidak mengerti mengapa orang tidak memilih solusi sederhana seperti ini. Sepertinya logis untuk melakukannya dengan cara ini jika Anda bertanya kepada saya.
Tom Dyer
3

Anda dapat melakukannya dengan mudah dengan camilan ouzo

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

atau dengan Array (dari barang ouzo)

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

Lihat: http://ouzo.readthedocs.org/en/latest/utils/functions.html#extract

Lihat juga pemrograman fungsional dengan ouzo (Saya tidak dapat memposting tautan).

woru
sumber
3

Peringatan create_function() telah DIHENTIKAN pada PHP 7.2.0. Mengandalkan fungsi ini sangat tidak disarankan.

Loop bawaan di PHP lebih cepat daripada loop yang diinterpretasikan, jadi masuk akal untuk membuat yang satu ini menjadi satu baris:

$result = array();
array_walk($cats, create_function('$value, $key, &$result', '$result[] = $value->id;'), $result)
Soulmerge
sumber
1
// $array that contain records and id is what we want to fetch a
$ids = array_column($array, 'id');
Rai Ahmad Fraz
sumber
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);

Keluaran : [1, 2]

daHormez
sumber
0

The create_function()fungsi ditinggalkan pada php v7.2.0 . Anda dapat menggunakan array_map()seperti yang diberikan,

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

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

Alternatifnya, Anda dapat menggunakan array_column()fungsi yang mengembalikan nilai dari satu kolom input, yang diidentifikasi oleh kunci_kolom. Secara opsional, kunci_indeks dapat disediakan untuk mengindeks nilai dalam larik yang dikembalikan dengan nilai dari kolom kunci_indeks dari larik masukan. Anda dapat menggunakan array_column seperti yang diberikan,

$IDs = array_column($array_of_object , 'id');
Kiran Maniya
sumber