この配列を考えます:
$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),
);
これどうやってするの?
あなたが正しい、あなたが探している関数は 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);
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では無名関数が導入されましたが、まだ宇宙船演算子はありません。 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に追加されました。
他の人がarray_multisort()
の使用を正しく提案していますが、何らかの理由でarray_column()
の存在を認めるような答えはないようで、これは解決策を大いに単純化することができます。だから私の提案は次のようになります。
array_multisort(array_column($inventory, 'price'), SORT_DESC, $inventory);
配列要素は文字列キーを持つ配列そのものなので、最善の策はカスタム比較関数を定義することです。それはとても速くて簡単です。これを試して:
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
)
)
私はこれで終わりました:
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');
あなたは usort
を無名関数と一緒に使うことができます。
usort($inventory, function ($a, $b) { return strnatcmp($a['price'], $b['price']); });
$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
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");
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*
}
この関数は再利用可能です:
function usortarr(&$array, $key, $callback = 'strnatcasecmp') {
uasort($array, function($a, $b) use($key, $callback) {
return call_user_func($callback, $a[$key], $b[$key]);
});
}
デフォルトでは文字列値でうまく機能しますが、 数値比較関数のコールバックをサブルーチン化する必要があります すべての値が数値の場合は/ /。
あなたはあなた自身の比較関数を定義してから usort を使うことを試みるかもしれません。
これは私がずっと前に見つけて、少し片付けた方法です。これはうまく機能し、オブジェクトを受け入れるように素早く変更することができます。
/**
* 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');
//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
)
)