เรียงลำดับอาร์เรย์ของวัตถุตามเขตข้อมูลวัตถุ


514

ฉันสามารถเรียงลำดับอาร์เรย์นี้ของวัตถุโดยหนึ่งในสาขาของตนเหมือนnameหรือcount?

  Array
(
    [0] => stdClass Object
        (
            [ID] => 1
            [name] => Mary Jane
            [count] => 420
        )

    [1] => stdClass Object
        (
            [ID] => 2
            [name] => Johnny
            [count] => 234
        )

    [2] => stdClass Object
        (
            [ID] => 3
            [name] => Kathy
            [count] => 4354
        )

   ....

คำตอบ:


699

ใช้usortนี่คือตัวอย่างที่ดัดแปลงมาจากคู่มือ:

function cmp($a, $b) {
    return strcmp($a->name, $b->name);
}

usort($your_data, "cmp");

คุณยังสามารถใช้callableเป็นอาร์กิวเมนต์ที่สอง นี่คือตัวอย่างบางส่วน:

นอกจากนี้หากคุณกำลังเปรียบเทียบค่าตัวเลขfn($a, $b) => $a->count - $b->countเนื่องจากฟังก์ชัน "เปรียบเทียบ" ควรทำเคล็ดลับ


93
นี่เป็นสิ่งที่ดี แต่ถ้าฟังก์ชันการเรียงลำดับอยู่ในคลาสเดียวกันกับฟังก์ชันการเรียกคุณควรใช้: usort ($ your_data, array ($ this, "cmp"));
rmooney

7
@ rmooney ใช่ แต่ถ้าคุณอยู่ในชั้นเรียน
cambraca

11
ใส่ความคิดเห็นแรกโดย @rmooneyในคำตอบของคุณ
Mohammad Faisal

7
หรือถ้าฟังก์ชั่นการเปรียบเทียบของคุณอยู่ในรูปแบบ / วัตถุที่คุณกำลังเปรียบเทียบ (ซึ่งเป็นการออกแบบที่สะอาดกว่าในความคิดของฉัน) คุณต้องรวมเนมสเปซเต็มรูปแบบกับโมเดล / วัตถุของคุณดังนี้: uasort ($ members, array ("Path \ to \ your \ Model \ Member "," comparByName "));
clauziere

3
นี้ไม่ได้ส่งฉันกลับไม่มีอะไรเรียงเพียงใหญ่ที่สุดก่อนและส่วนที่เหลือทั้งหมดฉัน unsort
Alberto Acuña

472

นี่เป็นวิธีที่ดีกว่าเมื่อใช้การปิด

usort($your_data, function($a, $b)
{
    return strcmp($a->name, $b->name);
});

โปรดทราบว่านี่ไม่ได้อยู่ในเอกสารของ PHP แต่ถ้าคุณใช้การปิด 5.3+ จะได้รับการสนับสนุนในกรณีที่สามารถให้อาร์กิวเมนต์ที่สามารถโทรได้


16
ฉันชอบอันนี้ดีกว่าคำตอบที่ยอมรับเนื่องจากเราสามารถกำหนดฟังก์ชั่นการเปรียบเทียบได้อย่างรวดเร็วและสามารถใช้ในชั้นเรียนได้
Nam G VU

11
ถ้าคุณต้องการเก็บคีย์อาเรย์ไว้ให้ใช้uasort()
gillytech

10
สำหรับเรียงเรียงลำดับ-1 * strcmp($a->name, $b->name);
Wallace Maxters

17
ไม่จำเป็นต้องคูณเพื่อเรียงเรียง เพียงแลกเปลี่ยน args:strcmp($b->name, $a->name)
zxcat

3
คุณอาจพบสถานการณ์เช่นฉันที่คำตอบที่ได้รับการยอมรับดีกว่านี้ ตัวอย่างเช่นคุณอาจมีผู้ปกครองและชั้นเรียนเด็ก คลาส child แทนที่ฟังก์ชันที่ใช้usortแต่ฟังก์ชันการเปรียบเทียบเหมือนกัน การใช้สิ่งนี้คุณต้องทำซ้ำรหัสสำหรับการปิดแทนการโทรไปยังprotected staticวิธีการที่คุณจะต้องกำหนดเพียงครั้งเดียวในคลาสผู้ปกครอง
Pere

48

หากคุณต้องการเรียงลำดับค่าจำนวนเต็ม:

// Desc sort
usort($array,function($first,$second){
    return $first->number < $second->number;
});

// Asc sort
usort($array,function($first,$second){
    return $first->number > $second->number;
});

อัพเดท ด้วยสตริงอย่าลืมแปลงเป็นรีจิสเตอร์เดียวกัน (บนหรือล่าง)

// Desc sort
usort($array,function($first,$second){
    return strtolower($first->text) < strtolower($second->text);
});

// Asc sort
usort($array,function($first,$second){
    return strtolower($first->text) > strtolower($second->text);
});

44

หากคุณใช้ php oop คุณอาจต้องเปลี่ยนเป็น:

public static function cmp($a, $b) 
{
    return strcmp($a->name, $b->name);
}

//in this case FUNCTION_NAME would be cmp
usort($your_data, array('YOUR_CLASS_NAME','FUNCTION_NAME')); 

28
usort($array, 'my_sort_function');

var_dump($array);

function my_sort_function($a, $b)
{
    return $a->name < $b->name;
}

รหัสเดียวกันจะอยู่กับcountสนาม

รายละเอียดเพิ่มเติมเกี่ยวกับusort: http://ru2.php.net/usort

Btw คุณได้รับชุดนั้นมาจากไหน? ฉันหวังว่าไม่ได้มาจากฐานข้อมูล?


1
ที่จริง$resultจะมีถ้ามันประสบความสำเร็จและการเปรียบเทียบของคุณควรจะTRUE $a->name > $b->name:)
cambraca

2
@cambraca: โอ้ลืมมันรับอาร์เรย์โดยอ้างอิง Btw, OP ไม่ได้บอกว่าเขาต้องเรียงลำดับอะไร
zerkms

1
ใช่แล้วมันเป็นฐานข้อมูล :) จริง ๆ แล้วจากฟังก์ชั่นที่รับข้อมูลจากฐานข้อมูล
Alex

3
@Alex: ทำไมคุณไม่เรียงมันในฐานข้อมูลล่ะ? ORDER BY count
zerkms

1
มันซับซ้อนกว่าเพราะนั่นเป็นส่วนหนึ่งของฟังก์ชั่นมาตรฐานของเวิร์ดเพรสและในขณะที่ฉันกำลังเขียนปลั๊กอินฉันไม่สามารถเปลี่ยนไฟล์ wp ได้ ฉันลองตัวอย่างของคุณโดยใช้ create_function (เพราะฉันใช้มันในชั้นเรียนและฉันไม่รู้วิธีส่งชื่อฟังก์ชั่นไปยัง usort): create_function('$a,$b', "return $a->count < $b->count;")แต่ฉันไม่สามารถทำให้มันใช้งานได้ :( ฉันได้รับการแจ้งเตือนเล็กน้อยและเตือนว่า usort คาดว่าพารามิเตอร์ 2 จะใช้การติดต่อกลับที่ถูกต้อง
Alex

9

คุณสามารถใช้ฟังก์ชั่นนี้ (ทำงานใน PHP Version> = 5.3):

function sortArrayByKey(&$array,$key,$string = false,$asc = true){
    if($string){
        usort($array,function ($a, $b) use(&$key,&$asc)
        {
            if($asc)    return strcmp(strtolower($a{$key}), strtolower($b{$key}));
            else        return strcmp(strtolower($b{$key}), strtolower($a{$key}));
        });
    }else{
        usort($array,function ($a, $b) use(&$key,&$asc)
        {
            if($a[$key] == $b{$key}){return 0;}
            if($asc) return ($a{$key} < $b{$key}) ? -1 : 1;
            else     return ($a{$key} > $b{$key}) ? -1 : 1;

        });
    }
}

ตัวอย่าง:

sortArrayByKey($yourArray,"name",true); //String sort (ascending order)
sortArrayByKey($yourArray,"name",true,false); //String sort (descending order)
sortArrayByKey($yourArray,"id"); //number sort (ascending order)
sortArrayByKey($yourArray,"count",false,false); //number sort (descending order)

ฉันใช้$a->{$key}และ$b->{$key}มากกว่า$a[$key]และ$b[$key]อย่างที่เราพูดอย่างเคร่งครัดจัดการกับคุณสมบัติมากกว่าสมาชิกอาเรย์ แต่นี่ก็ยังเป็นคำตอบที่ฉันกำลังมองหา
SteJ

โปรดใช้คำแนะนำของ @ SteJ ในโค้ดตัวอย่างเนื่องจากวิธีการแก้ปัญหาที่คุณให้เฉพาะกับวัตถุอย่างง่าย แต่ด้วยการแก้ไขของ SteJ มันใช้ได้กับทุกอาร์เรย์ของออบเจ็กต์ที่ฉันลองใช้
user2993145

6

คุณสามารถใช้usortเช่นนี้

usort($array,function($first,$second){
    return strcmp($first->name, $second->name);
});

5

หากทุกอย่างล้มเหลวที่นี่เป็นวิธีแก้ไขปัญหาอื่น:

$names = array(); 
foreach ($my_array as $my_object) {
    $names[] = $my_object->name; //any object field
}

array_multisort($names, SORT_ASC, $my_array);

return $my_array;

คุณควรได้รับรางวัลออสการ์สำหรับการแก้ปัญหานี้! ))))) Thankyou
Imeksbank

4

ข้อเสียของคำตอบทั้งหมดที่นี่คือพวกเขาใช้ชื่อเขตข้อมูลคงที่ดังนั้นฉันจึงเขียนรุ่นที่ปรับปรุงแล้วในรูปแบบ OOP สันนิษฐานว่าคุณจะใช้วิธีการ getter คุณโดยตรงสามารถใช้ชั้นนี้และใช้ชื่อเขตข้อมูลเป็นพารามิเตอร์ อาจมีคนพบว่ามีประโยชน์

class CustomSort{

    public $field = '';

    public function cmp($a, $b)
    {
        /**
         * field for order is in a class variable $field
         * using getter function with naming convention getVariable() we set first letter to uppercase
         * we use variable variable names - $a->{'varName'} would directly access a field
         */
        return strcmp($a->{'get'.ucfirst($this->field)}(), $b->{'get'.ucfirst($this->field)}());
    }

    public function sortObjectArrayByField($array, $field)
    {
        $this->field = $field;
        usort($array, array("Your\Namespace\CustomSort", "cmp"));;
        return $array;
    }
} 

3

ถ้าคุณต้องการเรียงลำดับวันที่

   usort($threads,function($first,$second){
        return strtotime($first->dateandtime) < strtotime($second->dateandtime);
    });

3

ทางเลือกง่าย ๆ ที่ช่วยให้คุณสามารถกำหนดฟิลด์ที่เรียงลำดับตามแบบไดนามิก:

$order_by = 'name';
usort($your_data, function ($a, $b) use ($order_by)
{
    return strcmp($a->{$order_by}, $b->{$order_by});
});

สิ่งนี้ขึ้นอยู่กับคลาสปิดซึ่งอนุญาตให้ใช้ฟังก์ชันที่ไม่ระบุชื่อ มีให้ตั้งแต่ PHP 5.3


2

หากคุณต้องการเปรียบเทียบสตริงตามท้องถิ่นคุณสามารถใช้แทนstrcollstrcmp

ใช้ Remeber เป็นครั้งแรกsetlocaleพร้อมLC_COLLATEตั้งค่าข้อมูลสถานที่หากจำเป็น

  usort($your_data,function($a,$b){
    setlocale (LC_COLLATE, 'pl_PL.UTF-8'); // Example of Polish language collation
    return strcoll($a->name,$b->name);
  });

2

หากคุณใช้สิ่งนี้ภายใน Codeigniter คุณสามารถใช้วิธีการดังต่อไปนี้

usort($jobs, array($this->job_model, "sortJobs"));  // function inside Model
usort($jobs, array($this, "sortJobs")); // Written inside Controller.

@rmooney ขอบคุณสำหรับคำแนะนำ มันช่วยฉันได้จริงๆ


Codeigniter นี้มีความเจาะจงเพียงใด?
ggdx

2

ขอบคุณสำหรับแรงบันดาลใจฉันต้องเพิ่มพารามิเตอร์ $ translator ภายนอกด้วย

usort($listable_products, function($a, $b) {
    global $translator;
    return strcmp($a->getFullTitle($translator), $b->getFullTitle($translator));
});

1

หากคุณต้องการจัดเรียงตามเขตข้อมูลเดียวเท่านั้นก็usortเป็นตัวเลือกที่ดี อย่างไรก็ตามการแก้ปัญหาอย่างรวดเร็วกลายเป็นยุ่งเหยิงถ้าคุณต้องการที่จะเรียงลำดับตามหลายสาขา ในกรณีนี้สามารถใช้YaLinqo library * ซึ่งใช้ไวยากรณ์เคียวรีคล้าย SQL สำหรับอาร์เรย์และวัตถุ มันมีไวยากรณ์สวยสำหรับทุกกรณี:

$sortedByName         = from($objects)->orderBy('$v->name');
$sortedByCount        = from($objects)->orderBy('$v->count');
$sortedByCountAndName = from($objects)->orderBy('$v->count')->thenBy('$v->name');

นี่'$v->count'คือการจดชวเลขสำหรับfunction ($v) { return $v->count; }(สามารถใช้) กลุ่มเมธอดเหล่านี้ส่งคืนตัววนซ้ำ แต่คุณสามารถรับอาร์เรย์ได้โดยเพิ่ม->toArray()ท้ายถ้าคุณต้องการ

* พัฒนาโดยฉัน


1

คุณสามารถใช้ฟังก์ชั่นเรียงลำดับจากNspl :

use function \nspl\a\sorted;
use function \nspl\op\propertyGetter;
use function \nspl\op\methodCaller;

// Sort by property value
$sortedByCount = sorted($objects, propertyGetter('count'));

// Or sort by result of method call
$sortedByName = sorted($objects, methodCaller('getName'));

โปรดอธิบายว่าเพราะเหตุใด OP จึงจำเป็นต้องมีห้องสมุดเพิ่มเติมเพื่อให้สิ่งอำนวยความสะดวกได้รับการแก้ไขโดยฟังก์ชั่นที่สร้างขึ้น
ggdx

1

นี่คือสิ่งที่ฉันมีสำหรับคลาสยูทิลิตี้

class Util
{
    public static function sortArrayByName(&$arrayToSort, $meta) {
        usort($arrayToSort, function($a, $b) use ($meta) {
            return strcmp($a[$meta], $b[$meta]);
        });
    }
}

เรียกมันว่า:

Util::sortArrayByName($array, "array_property_name");

1

คุณสามารถใช้ usort เช่นนี้

หากคุณต้องการเรียงลำดับตามหมายเลข:

function cmp($a, $b)
{
    if ($a == $b) {
        return 0;
    }
    return ($a < $b) ? -1 : 1;
}

$a = array(3, 2, 5, 6, 1);

usort($a, "cmp");

หรือตัวอักษร abc:

function cmp($a, $b)
{
    return strcmp($a["fruit"], $b["fruit"]);
}

$fruits[0]["fruit"] = "lemons";
$fruits[1]["fruit"] = "apples";
$fruits[2]["fruit"] = "grapes";

usort($fruits, "cmp");

ดูเพิ่มเติมได้ที่: https://www.php.net/manual/th/function.usort.php

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