PHP - การแยกคุณสมบัติจากอาร์เรย์ของวัตถุ


128

ฉันมีวัตถุแมวมากมาย:

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

และฉันต้องการแยกอาร์เรย์ของ ID ของแมวใน 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
นี่เป็นคำตอบที่ดีที่สุด
Dmitry Buslaev

1
ทางออกที่ดีที่สุด แต่ใช้ได้กับ php 5.5 ขึ้นไปเท่านั้น
Ludo - ปิดการบันทึก

2
ไม่มีใครควรเข้ารหัสด้วย 5.5 อีกต่อไป เวอร์ชันภาษาโปรแกรม 3.5 ปี ...
Toskan

11
การแก้ปัญหานี้ไม่ได้ตอบคำถามเพราะarray_columnไม่ได้ทำงานกับarrayของobjects ที่ทั้งหมด เนื่องจาก PHP 7.0.0 เป็นไปได้: stackoverflow.com/a/23335938/655224
algorhythm

1
ใช้งานได้เฉพาะเมื่อคุณสมบัติของวัตถุมีการเข้าถึงแบบสาธารณะ
Karol Gasienica

154

คำเตือน create_function()ถูกยกเลิกเมื่อ PHP 7.2.0 การใช้ฟังก์ชันนี้เป็นสิ่งที่ไม่ควรทำอย่างยิ่ง

คุณสามารถใช้array_map()ฟังก์ชัน
สิ่งนี้ควรทำ:

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

54
นี่เป็นวิธีแก้ปัญหาที่ถูกต้องและจะนำไปสู่ความจริงที่ว่าผู้ดูแลที่จะเกิดขึ้นทุกคนจะเป็น "wtf" 'd: D
Andreas Klinger

4
สิ่งเดียวที่ฉันไม่ชอบเกี่ยวกับโซลูชันนี้คือการใช้ create_function
Ionuț G. Stan

4
คุณสามารถใช้ฟังก์ชันแลมบ์ดาได้ แต่มีคนไม่มากนักที่จะใช้ PHP 5.3
Greg

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

87

วิธีแก้ปัญหาขึ้นอยู่กับเวอร์ชัน PHP ที่คุณใช้ อย่างน้อยมี 2 วิธีแก้ไข:

First (PHP เวอร์ชันใหม่กว่า)

ดังที่ @JosepAlsina กล่าวไว้ก่อนหน้านี้วิธีแก้ปัญหาที่ดีที่สุดและสั้นที่สุดคือใช้array_columnดังต่อไปนี้:

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

ข้อสังเกต: สำหรับการวนซ้ำes arrayที่มี\stdClassอยู่ในคำถามนั้นทำได้เฉพาะกับเวอร์ชัน PHP >= 7.0เท่านั้น แต่เมื่อใช้arrayมีarrays คุณสามารถทำเช่นเดียวกันตั้งแต่ >= 5.5PHP

วินาที (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);


ความแตกต่าง

วิธีแก้ปัญหาแรกสร้างฟังก์ชันใหม่และใส่ลงในแรมของคุณ ตัวรวบรวมขยะไม่ลบอินสแตนซ์ฟังก์ชันที่สร้างไว้แล้วและเรียกแล้วออกจากหน่วยความจำด้วยเหตุผลบางประการ และไม่ว่าจะเป็นอย่างไรอินสแตนซ์ฟังก์ชันที่สร้างขึ้นจะไม่สามารถถูกเรียกได้อีกเพราะเราไม่มีตัวชี้ และในครั้งต่อไปเมื่อมีการเรียกรหัสนี้ฟังก์ชันเดิมจะถูกสร้างขึ้นอีกครั้ง พฤติกรรมนี้เติมเต็มความทรงจำของคุณอย่างช้าๆ ...

ทั้งสองตัวอย่างพร้อมเอาต์พุตหน่วยความจำเพื่อเปรียบเทียบ:

BAD

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


นอกจากนี้ยังอาจกล่าวถึงที่นี่

ความจำรั่ว?! Garbage Collector ทำถูกต้องหรือไม่เมื่อใช้ "create_function" ภายใน "array_map"


แม้ว่าฉันจะใช้ php 7.2 แต่ดูเหมือนว่าโซลูชันจะไม่ทำงานหากคุณใช้อ็อบเจ็กต์คลาสเนมสเปซและส่งคืนอาร์เรย์ว่าง
มูฮัมหมัดโอเมอร์อัสลาม

โพสต์หาประโยชน์ได้ไหม ตัวอย่างสั้น ๆ เพื่อให้เข้าใจบริบทของคุณดีขึ้นหรือไม่?
algorhythm

ตัวอย่างเช่นดูตัวอย่างนี้ที่ฉันมีรายการของโมเดลออบเจ็กต์ที่ส่งคืนโดย dropbox API SDK และเมื่อเราพยายามใช้array_columnกับอาร์เรย์นี้จะส่งคืนค่าว่างเสมอในขณะที่ข้อมูลโค้ดนี้ทำงานได้อย่างถูกต้องทั้งสองมีคุณสมบัติที่ได้รับการป้องกันซึ่งสามารถเข้าถึงได้ในตัวอย่างที่สอง เท่านั้น ฉันไม่พบเหตุผลอื่นนอกจากเนมสเปซ
Muhammad Omer Aslam

เมื่อฉันเขียนobjectในโซลูชันของฉันฉันหมายถึงobjectไม่ใช่Objectไฟล์. lowercased อธิบายถึงวัตถุที่เรียบง่ายobject \stdClassบางทีนั่นอาจเป็นปัญหา ของคุณObjectมีtoArrayวิธีการหรือไม่? ใช้สิ่งนี้ ง่ายobjectและarrayเกือบจะเหมือนกัน ((object)(array)$o) === $oต่อไปนี้คงต้องถูกต้อง: เมื่อใช้__getวิธีการคุณจะทำให้คุณสมบัติคลาสของคุณสามารถเข้าถึงได้สำหรับทุกคน นี่อาจเป็นพฤติกรรมที่คาดหวัง แต่คุณสามารถทำซ้ำได้array<Object>เช่นกันด้วยarray_mapและโทรtoArray(ถ้ามี) จากนั้นมันก็ใช้งานได้เช่นกัน
algorhythm

ตัวอย่างที่สองที่ฉันให้มานั้นมาจาก php, net และใช้คลาสออบเจ็กต์เดียวกันกับในตัวอย่างแรกบางทีคุณอาจจะถูกต้องอาจเป็นอย่างอื่นฉันจะลองโดยการแปลงเป็นอาร์เรย์ขอบคุณ
Muhammad Omer Aslam

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

ฉันรู้ว่ามันใช้การวนซ้ำ แต่เป็นวิธีที่ง่ายที่สุด! และการใช้ฟังก์ชั่นมันยังคงจบลงที่บรรทัดเดียว


ฉันไม่เข้าใจว่าทำไมผู้คนถึงไม่เลือกใช้วิธีง่ายๆเช่นนี้ ดูเหมือนจะมีเหตุผลที่จะทำเช่นนี้ถ้าคุณถามฉัน
Tom Dyer

3

คุณสามารถทำได้ง่ายๆด้วยสารพัด ouzo

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

หรือกับอาร์เรย์ (จากสารพัด ouzo)

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

ตรวจสอบ: http://ouzo.readthedocs.org/en/latest/utils/functions.html#extract

ดูการเขียนโปรแกรมเชิงฟังก์ชันด้วย ouzo (ฉันไม่สามารถโพสต์ลิงค์ได้)


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 เพื่อจัดทำดัชนีค่าในอาร์เรย์ที่ส่งคืนโดยค่าจากคอลัมน์ index_key ของอาร์เรย์อินพุต คุณสามารถใช้ array_column ตามที่กำหนด

$IDs = array_column($array_of_object , 'id');
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.