オブジェクトの配列をオブジェクトフィールドで並べ替え


514

nameまたはのように、このオブジェクトの配列をそのフィールドの1つでソートするにはどうすればよい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");

2番目の引数として任意の呼び出し可能オブジェクトを使用することもできます。ここではいくつかの例を示します。

  • 匿名関数の使用(PHP 5.3以降)

    usort($your_data, function($a, $b) {return strcmp($a->name, $b->name);});
  • クラスの中から

    usort($your_data, array($this, "cmp")); // "cmp" should be a method in the class
  • アロー関数の使用(PHP 7.4以降)

    usort($your_data, fn($a, $b) => strcmp($a->name, $b->name));

また、数値を比較している場合はfn($a, $b) => $a->count - $b->count、「比較」機能でうまくいくはずです。


93
これはすばらしいことですが、ソート関数が呼び出し元の関数と同じクラスにある場合は、次のように使用する必要があります。usort($ your_data、array($ this、 "cmp"));
rmooney 2013

7
@rmooneyはい。ただし、クラス内にいる場合のみ。
cambraca 2013


7
または、比較する関数が比較対象のモデル/オブジェクト内にある場合(これは私の考えではよりクリーンな設計です)、次のように完全な名前空間をモデル/オブジェクトに含める必要があります:uasort($ members、array( "Path \ to \ your \ Model \ Member "、" compareByName "));
clauziere 14

3
このいけないリターン私の何がちょうど最も大きなまず、ソートしない、とのunsortすべての残りの部分I
アルベルト・アクーニャ

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
descをソートするために乗算する必要はありません。ただ、スワップ引数:strcmp($b->name, $a->name)
zxcat

3
私のように、受け入れられた答えがこの答えよりも好ましい状況に遭遇するかもしれません。たとえば、親クラスと子クラスがあるとします。子クラスusortは、使用する関数をオーバーライドしますが、比較関数は同じです。これを使用protected staticすると、親クラスで一度だけ定義する必要があるメソッドを呼び出す代わりに、クロージャーのコードを複製する必要があります。
ペレ

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フィールドで使用されます。

詳細usorthttp : //ru2.php.net/usort

ところで、その配列はどこから入手したのですか?データベースからではないことを願っていますか?


1
実際$resultにはTRUE、成功した場合に含まれ、比較はになります$a->name > $b->name。:)
cambraca 2010年

2
@cambraca:ああ、参照で配列を受け付けるのを忘れた ところで、OPはコレクションを並べ替える必要がある順序を明らかにしなかった。
zerkms 2010年

1
はい、それはデータベースです:)実際には、データベースからデータを取得する関数から
Alex

3
@アレックス:では、なぜデータベースでソートしないのですか?ORDER BY count
zerkms 2010年

1
それはwordpressの標準機能の一部であり、プラグインを作成しているため、wpファイルを変更することができないため、より複雑です。create_functionを使用して例を試しました(クラス内で使用していて、関数名をusortに渡す方法がわからcreate_function('$a,$b', "return $a->count < $b->count;")ないため):しかし、機能させることはできません:( usortはパラメーター2が有効なコールバックであることを期待しています
Alex

9

この関数を使用できます(PHPバージョン> = 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 2016年

実装してください@あなただけ与える解決策として、サンプルコードでは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;

あなたはこの解決策のためにオスカーを手に入れるべきです!)))))
ありがとう

4

ここでのすべての答えの欠点は、静的フィールド名を使用することです。そのため、調整されたバージョンをOOPスタイルで作成しました。ゲッターメソッドを使用していると仮定すると、このクラスを直接使用し、フィールド名をパラメーターとして使用できます。おそらく誰かがそれを便利だと思うでしょう。

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

これは、無名関数を許可するClosureクラスに基づいています。PHP 5.3以降で使用できます。


2

ローカルベースの文字列比較が必要な場合は、strcoll代わりに使用できますstrcmp

最初の使用を思い出してくれるsetlocaleLC_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 2018

2

インスピレーションのおかげで、外部の$ translatorパラメーターも追加する必要がありました

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

1

1つのフィールドのみで並べ替える必要がある場合usortは、この方法が適しています。ただし、複数のフィールドで並べ替える必要がある場合、ソリューションはすぐに乱雑になります。この場合、配列とオブジェクトに対してSQLのようなクエリ構文を実装するYaLinqoライブラリ*を使用できます。それはすべての場合にかなりの構文を持っています:

$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 char:

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/en/function.usort.php

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.