web-dev-qa-db-ja.com

PHPで与えられたキーの値で連想配列の配列をソートするにはどうすればいいですか?

この配列を考えます:

$inventory = array(

   array("type"=>"fruit", "price"=>3.50),
   array("type"=>"milk", "price"=>2.90),
   array("type"=>"pork", "price"=>5.43),

);

$inventoryの要素を価格でソートしたい

$inventory = array(

   array("type"=>"pork", "price"=>5.43),
   array("type"=>"fruit", "price"=>3.50),
   array("type"=>"milk", "price"=>2.90),

);

これどうやってするの?

365
Matt

あなたが正しい、あなたが探している関数は array_multisort() です。

これはマニュアルから直接取り出してあなたのケースに合わせた例です:

$price = array();
foreach ($inventory as $key => $row)
{
    $price[$key] = $row['price'];
}
array_multisort($price, SORT_DESC, $inventory);

PHP 5.5.0以降では、そのforeachの代わりにarray_column()を使用できます。

$price = array_column($inventory, 'price');

array_multisort($price, SORT_DESC, $inventory);
501
Josh Davis

PHP 7以降

PHP 7以降、 usort無名関数スペースシップ演算子 を使用して要素を比較することで、これを簡潔に行うことができます。

あなたはこのような昇順のソートをすることができます:

usort($inventory, function ($item1, $item2) {
    return $item1['price'] <=> $item2['price'];
});

または、このような降順の並べ替え

usort($inventory, function ($item1, $item2) {
    return $item2['price'] <=> $item1['price'];
});

これがどのように機能するかを理解するために、usortはユーザー提供の比較関数を取り、それは以下のように振舞う必要があります(docsから):

比較関数は、最初の引数がそれぞれ2番目の引数よりも小さい、等しい、または大きいと見なされる場合、ゼロ以下、ゼロ以上の整数を返さなければなりません。

また、宇宙船の運営者である<=>は、

両方のオペランドが等しい場合は0、左が大きい場合は1、右が大きい場合は-1を返します。

これはまさにusortが必要とするものです。実際のところ、 https://wiki.php.net/rfc/combined-comparison-operator の言語に<=>を追加したことの正当性は、ほぼすべてです。

usort()で使用するための順序付けコールバックを書くのをより簡単にします


PHP 5.3以降

PHP 5.3では無名関数が導入されましたが、まだ宇宙船演算子はありません。 usortを使って配列をソートすることはできますが、もう少し冗長で理解が困難です。

usort($inventory, function ($item1, $item2) {
    if ($item1['price'] == $item2['price']) return 0;
    return $item1['price'] < $item2['price'] ? -1 : 1;
});

$item2['price'] - $item1['price']のように、整数値を扱うコンパレータが単に値の差を返すのはごく普通のことですが、この場合、は安全にはできません。質問者の例では価格は浮動小数点数ですが、usortに渡す比較関数はusortが正しく機能するために整数を返さなければなりません。

Floatなど、比較関数からnon-integerの値を返すと、コールバックの戻り値の整数に内部キャストされます。そのため、0.99や0.1などの値は両方とも0の整数値にキャストされます。これは、そのような値を等しいと比較します。

これは、PHP 5.xでusortを使用するときに留意する必要がある重要な罠です。 この答えの私のオリジナル版 この間違いを犯したが、それでも私は何千人もの見解に対して10人の賛成票を投じたが、誰もが深刻なバグに気付かずにいた。私のような欠点がコンパレータ関数を台無しにすることができるのは、正確にであるため、使いやすい宇宙船の演算子がPHP 7に追加されました。

245
Mark Amery

他の人がarray_multisort()の使用を正しく提案していますが、何らかの理由でarray_column()の存在を認めるような答えはないようで、これは解決策を大いに単純化することができます。だから私の提案は次のようになります。

array_multisort(array_column($inventory, 'price'), SORT_DESC, $inventory);
60

配列要素は文字列キーを持つ配列そのものなので、最善の策はカスタム比較関数を定義することです。それはとても速くて簡単です。これを試して:

function invenDescSort($item1,$item2)
{
    if ($item1['price'] == $item2['price']) return 0;
    return ($item1['price'] < $item2['price']) ? 1 : -1;
}
usort($inventory,'invenDescSort');
print_r($inventory);

以下を生成します。

Array
(
    [0] => Array
        (
            [type] => pork
            [price] => 5.43
        )

    [1] => Array
        (
            [type] => fruit
            [price] => 3.5
        )

    [2] => Array
        (
            [type] => milk
            [price] => 2.9
        )

)
40
zombat

私はこれで終わりました:

function sort_array_of_array(&$array, $subfield)
{
    $sortarray = array();
    foreach ($array as $key => $row)
    {
        $sortarray[$key] = $row[$subfield];
    }

    array_multisort($sortarray, SORT_ASC, $array);
}

配列と第2レベル配列のフィールド名を渡して、関数を呼び出すだけです。好きです:

sort_array_of_array($inventory, 'price');
23
Danielzt

あなたは usort を無名関数と一緒に使うことができます。

usort($inventory, function ($a, $b) { return strnatcmp($a['price'], $b['price']); });
15
kenorb
$inventory = 
    array(array("type"=>"fruit", "price"=>3.50),
          array("type"=>"milk", "price"=>2.90),
          array("type"=>"pork", "price"=>5.43),
          );

function pricesort($a, $b) {
  $a = $a['price'];
  $b = $b['price'];
  if ($a == $b)
    return 0;
  return ($a > $b) ? -1 : 1;
}

usort($inventory, "pricesort");
// uksort($inventory, "pricesort");

print("first: ".$inventory[0]['type']."\n\n");
// for usort(): prints milk (item with lowest price)
// for uksort(): prints fruit (item with key 0 in the original $inventory)

// foreach prints the same for usort and uksort.
foreach($inventory as $i){
  print($i['type'].": ".$i['price']."\n");
}

出力:

first: pork

pork: 5.43
fruit: 3.5
milk: 2.9
9
danamlund

From php の与えられたキーの値で連想配列の配列をソートする:

uasort( http://php.net/uasort )を使用すると、独自に定義した関数で配列をソートできます。あなたの場合、それは簡単です:

$array = array(
  array('price'=>'1000.50','product'=>'test1'),
  array('price'=>'8800.50','product'=>'test2'),
  array('price'=>'200.0','product'=>'test3')
);

function cmp($a, $b) {
  return $a['price'] > $b['price'];
}

uasort($array, "cmp");
4
Kamal

100 000レコードでテストされました。 秒単位の時間(funciton microtimeで計算)。 キー位置のソートに関する一意の値に対してのみ。

@Josh Davisの関数の解決策: 経過時間 :1.5768740177155

地雷解決策: 経過時間 :0.094044923782349

解決策:

function SortByKeyValue($data, $sortKey, $sort_flags=SORT_ASC)
{
    if (empty($data) or empty($sortKey)) return $data;

    $ordered = array();
    foreach ($data as $key => $value)
        $ordered[$value[$sortKey]] = $value;

    ksort($ordered, $sort_flags);

    return array_values($ordered); *// array_values() added for identical result with multisort*
}
4
Nefelim

この関数は再利用可能です:

function usortarr(&$array, $key, $callback = 'strnatcasecmp') {
    uasort($array, function($a, $b) use($key, $callback) {
        return call_user_func($callback, $a[$key], $b[$key]);
    });
}

デフォルトでは文字列値でうまく機能しますが、 数値比較関数のコールバックをサブルーチン化する必要があります すべての値が数値の場合は/ /。

2
mpen

あなたはあなた自身の比較関数を定義してから usort を使うことを試みるかもしれません。

2
Alex Sexton

これは私がずっと前に見つけて、少し片付けた方法です。これはうまく機能し、オブジェクトを受け入れるように素早く変更することができます。

/**
 * A method for sorting arrays by a certain key:value.
 * SortByKey is the key you wish to sort by
 * Direction can be ASC or DESC.
 *
 * @param $array
 * @param $sortByKey
 * @param $sortDirection
 * @return array
 */
private function sortArray($array, $sortByKey, $sortDirection) {

    $sortArray = array();
    $tempArray = array();

    foreach ( $array as $key => $value ) {
        $tempArray[] = strtolower( $value[ $sortByKey ] );
    }

    if($sortDirection=='ASC'){ asort($tempArray ); }
        else{ arsort($tempArray ); }

    foreach ( $tempArray as $key => $temp ){
        $sortArray[] = $array[ $key ];
    }

    return $sortArray;

}

メソッドを変更してオブジェクトをソートするには、単に次の行を変更します。

$tempArray[] = strtolower( $value[ $sortByKey ] );から$tempArray[] = strtolower( $value->$sortByKey );

メソッドを実行するには単純に

sortArray($inventory,'price','ASC');

1
Kray
//Just in one line custom function
function cmp($a, $b)
{
return (float) $a['price'] < (float)$b['price'];
}
@uasort($inventory, "cmp");
print_r($inventory);

//result

Array
(
[2] => Array
    (
        [type] => pork
        [price] => 5.43
    )

[0] => Array
    (
        [type] => fruit
        [price] => 3.5
    )

[1] => Array
    (
        [type] => milk
        [price] => 2.9
    )

)
1
Kamal