PHP - Trích xuất một thuộc tính từ một mảng các đối tượng


128

Tôi đã có một loạt các đối tượng mèo:

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

và tôi muốn trích xuất một mảng ID của mèo trong 1 dòng (không phải là hàm cũng không phải vòng lặp).

Tôi đã suy nghĩ về việc sử dụng array_walkvới create_functionnhưng tôi không biết làm thế nào để làm điều đó.

Bất kỳ ý tưởng?


Tôi không muốn sử dụng vòng lặp vì tôi muốn có thể gán kết quả trong 1 dòng: $ cat_id = myfeft ($ cat); / * nên trả về Mảng (15, 18, 23) * /
abernier

Câu trả lời:


149

Nếu bạn có PHP 5.5 trở lên , cách tốt nhất là sử dụng hàm dựng sẵn array_column():

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

Nhưng con trai phải là một mảng hoặc được chuyển đổi thành một mảng


12
Đây thực sự là câu trả lời hay nhất
Dmitry Buslaev

1
Giải pháp tốt nhất, nhưng chỉ khả dụng cho php 5.5 trở lên
Ludo - Tắt bản ghi

2
không ai nên mã hóa nữa với 5.5. Phiên bản ngôn ngữ lập trình 3,5 năm tuổi ...
Toskan

11
Giải pháp này không trả lời câu hỏi vì, array_columnhoàn toàn không hoạt động với một arraytrong số objectđó. Vì PHP 7.0.0 là có thể: stackoverflow.com/a/23335938/655224
algor nhịp

1
Nó chỉ hoạt động khi tài sản đối tượng có quyền truy cập công cộng.
Karol Gasienica

154

Cảnh báo create_function() đã được ĐỔI kể từ phiên bản PHP 7.2.0. Dựa vào chức năng này là rất nản lòng.

Bạn có thể sử dụng array_map()chức năng.
Điều này nên làm điều đó:

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

54
đây là giải pháp chính xác và sẽ dẫn đến thực tế là mọi nhà bảo trì sắp tới sẽ là "wtf" 'd: D
Andreas Klinger

4
Điều duy nhất mà tôi không thích về giải pháp này là việc sử dụng create_function.
Ionuț G. Stan

4
Bạn có thể sử dụng hàm lambda nhưng không nhiều người sẽ chạy PHP 5.3
Greg

26
Ở đây chúng tôi đi: $project_names = array_map(function($project) { return $project->name ;}, $projects );Tuy nhiên, lưu ý trong bài đăng trên blog này rằng nó có thể chậm hơn 2,5 lần / bộ nhớ chuyên sâu theo cách này.
Tương đối

7
Tôi phát hiện ra rằng mọi lúc khi chức năng được tạo ra với create_functionbộ nhớ đang tăng lên. Nếu bạn viết một chương trình với các vòng lặp vô hạn và gọi array_mapvới create_functionnó trong đó Out of memory...đôi khi bạn sẽ gặp lỗi. Vì vậy, không sử dụng create_functionvà sử dụngarray_map(function($o) { return $o->id; }, $objects);
algorardi

87

Giải pháp phụ thuộc vào phiên bản PHP bạn đang sử dụng. Ít nhất có 2 giải pháp:

Đầu tiên (Phiên bản PHP mới hơn)

Như @JosepAlsina đã nói trước giải pháp tốt nhất và cũng ngắn nhất là sử dụng array_columnnhư sau:

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

Lưu ý: Để lặp lại một es arraycó chứa \stdClassnhư được sử dụng trong câu hỏi, chỉ có thể với các phiên bản PHP >= 7.0. Nhưng khi sử dụng một s arraycó chứa arraybạn có thể làm tương tự kể từ PHP >= 5.5.

Thứ hai (Phiên bản PHP cũ hơn)

@Greg cho biết trong các phiên bản PHP cũ hơn có thể thực hiện như sau:

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

Nhưng hãy cẩn thận: Trong các phiên bản PHP mới hơn >= 5.3.0, tốt hơn là sử dụng Closures, như sau:

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


Sự khác biệt

Giải pháp đầu tiên tạo ra một chức năng mới và đưa nó vào RAM của bạn. Vì một số lý do, trình thu gom rác không xóa cá thể hàm đã được tạo và đã gọi ra khỏi bộ nhớ. Và bất kể thực tế là gì, cá thể hàm được tạo không bao giờ có thể được gọi lại, bởi vì chúng ta không có con trỏ cho nó. Và lần sau khi mã này được gọi, chức năng tương tự sẽ được tạo lại. Hành vi này từ từ lấp đầy bộ nhớ của bạn ...

Cả hai ví dụ với đầu ra bộ nhớ để so sánh chúng:

XẤU

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

TỐT

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

    echo memory_get_usage() . "\n";

    sleep(1);
}

// the output
4235136
4235168
4235168
4235168
...


Điều này cũng có thể được thảo luận ở đây

Bộ nhớ bị rò rỉ?! Garbage Collector có hoạt động tốt khi sử dụng 'create_function' trong 'Array_map' không?


mặc dù tôi đang sử dụng php 7.2 nhưng có vẻ như giải pháp sẽ không hoạt động nếu bạn đang sử dụng các đối tượng lớp không gian tên và trả về mảng trống.
Muhammad Omer Aslam

Bạn có thể đăng một khai thác? Một đoạn ngắn để hiểu ngữ cảnh của bạn tốt hơn?
algorardi

chẳng hạn, hãy xem đoạn mã này nơi tôi có một danh sách các đối tượng mô hình được trả về bởi SDK API của dropbox và khi chúng tôi cố gắng sử dụng array_columntrên mảng này, nó luôn trả về trống trong khi đoạn trích NÀY hoạt động chính xác, cả hai đều có thuộc tính được bảo vệ có thể truy cập được trong đoạn mã thứ hai chỉ có. Tôi không thể tìm thấy bất kỳ lý do nào khác ngoài không gian tên.
Muhammad Omer Aslam

Khi tôi viết objecttrong giải pháp của tôi, tôi có nghĩa là objectkhông phải là một Object. Các objectmô tả thấp hơn mô tả các đối tượng đơn giản \stdClass. Có lẽ đó là vấn đề. Bạn Objectcó một toArrayphương pháp? Dùng cái này. Một đơn giản objectvà an arraylà gần như nhau. Sau bất biến phải hợp lệ : ((object)(array)$o) === $o. Khi thực hiện __getphương pháp, bạn sẽ làm cho các thuộc tính lớp của bạn có thể truy cập được cho mọi người. Đây có thể là hành vi dự kiến. Nhưng bạn cũng có thể lặp lại array<Object>ví dụ của mình bằng array_mapvà gọi toArray(nếu có) và sau đó CNTT cũng hoạt động
algorardi

đoạn mã thứ hai tôi cung cấp là từ php, net và sử dụng cùng một đối tượng Class như trong đoạn mã đầu tiên, có lẽ bạn đúng có thể là thứ gì đó khác tôi sẽ thử bằng cách chuyển đổi nó thành một mảng thankyou.
Muhammad Omer Aslam

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

và sử dụng nó trong một dòng :

$ids = extract_ids($cats);

1
Cảm ơn SilentGhost, nhưng câu hỏi của tôi sắp nhận được $ res chỉ trong 1 lệnh, không sử dụng vòng lặp ...
abernier

2
Điều gì khác biệt nó làm? Đây là về thẳng như nó được. Có lẽ bạn sẽ sử dụng nhiều dòng hơn bằng cách sử dụng một cái gì đó như array_walk.
lừa dối

@deceze, một giải pháp thanh lịch, đơn giản và ngắn gọn trông có vẻ tốt hơn - đặc biệt đối với một cái gì đó rất dễ giải thích vì thao tác này (ví dụ: đây không phải là logic tùy chỉnh có nhiều không gian và nhận xét). Đối với tôi, điều đó làm cho một sự khác biệt lớn.
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);

?>

ĐẦU RA

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

Tôi biết nó sử dụng một vòng lặp, nhưng đó là cách đơn giản nhất để làm điều đó! Và sử dụng một chức năng, nó vẫn kết thúc trên một dòng duy nhất.


Tôi không hiểu tại sao mọi người không chọn giải pháp đơn giản như thế này. Có vẻ hợp lý để làm theo cách này nếu bạn hỏi tôi.
Tom Dyer


3

Cảnh báo create_function() đã được ĐỔI kể từ phiên bản PHP 7.2.0. Dựa vào chức năng này là rất nản lòng.

Các vòng lặp dựng sẵn trong PHP nhanh hơn các vòng lặp được giải thích, do đó, thực sự có ý nghĩa để biến cái này thành một lớp lót:

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

1
// $array that contain records and id is what we want to fetch a
$ids = array_column($array, 'id');

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

Đầu ra : [1, 2]


0

Các create_function()chức năng bị phản đối như của php v7.2.0 . Bạn có thể sử dụng array_map()như đã cho,

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

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

Ngoài ra, bạn có thể sử dụng array_column()hàm trả về các giá trị từ một cột duy nhất của đầu vào, được xác định bởi cột_key. Theo tùy chọn, một index_key có thể được cung cấp để lập chỉ mục các giá trị trong mảng được trả về bởi các giá trị từ cột index_key của mảng đầu vào. Bạn có thể sử dụng mảng_column như đã cho,

$IDs = array_column($array_of_object , 'id');
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.