Как отсортировать массив ассоциативных массивов по значению заданного ключа в PHP?
учитывая этот массив:
$inventory = array(
array("type"=>"fruit", "price"=>3.50),
array("type"=>"milk", "price"=>2.90),
array("type"=>"pork", "price"=>5.43),
);
Я хочу вроде по цене для:
$inventory = array(
array("type"=>"pork", "price"=>5.43),
array("type"=>"fruit", "price"=>3.50),
array("type"=>"milk", "price"=>2.90),
);
как я могу это сделать?
16 ответов
вы правы, функция, которую вы ищете, это array_multisort()
.
вот пример, взятый прямо из руководства и адаптировать к вашему случаю:
$price = array();
foreach ($inventory as $key => $row)
{
$price[$key] = $row['price'];
}
array_multisort($price, SORT_DESC, $inventory);
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
принимает пользовательскую функцию сравнения, которая должна вести себя следующим образом (из документов):
функция сравнения должна возвращать целое, которое меньше, равно или больше нуля, если первый аргумент является соответственно меньшим, равным или большим чем второй.
и обратите внимание, что <=>
оператор космолет,
возвращает 0, если оба операнда равны, 1, если левый больше, и 1, если справа больше
именно что?!--3--> потребности. На самом деле, почти все оправдание для добавления <=>
языка 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']
, мы не могу безопасно делать в этом случае. Это связано с тем, что цены являются числами с плавающей запятой в примере вопроса asker, но функцию сравнения мы передаем в usort
должен возвращать целые числа для usort
работу:
возвращение нецелым значения из функции сравнения, такие как float, приведут к внутреннему приведению к целому числу возвращаемого значения обратного вызова. Таким образом, такие значения, как 0.99 и 0.1, будут приведены к целочисленному значению 0, которое будет сравнивать такие значения как equal.
это важная ловушка, чтобы иметь в виду при использовании usort
в PHP 5.x! моя первоначальная версия этого ответа сделал эту ошибку, и все же я накопил десять upvotes более тысячи просмотров, по-видимому, никто не заметил серьезной ошибки. Легкость, с которой lackwits как я могу запороть функции компаратора точно причина того, что более простой в использовании оператор космического корабля был добавлен к языку в PHP 7.
поскольку элементы массива сами являются массивами со строковыми ключами, лучше всего определить пользовательскую функцию сравнения. Это довольно быстро и легко сделать. Попробуйте это:
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
)
)
в то время как другие правильно предложил использовать array_multisort()
, по какой-то причине ни один ответ, похоже, не признает существования array_column()
, который может значительно упростить решение. Поэтому мое предложение было бы:
array_multisort(array_column($inventory, 'price'), SORT_DESC, $inventory);
Я закончил на этом:
function sort_array_of_array(&$array, $subfield)
{
$sortarray = array();
foreach ($array as $key => $row)
{
$sortarray[$key] = $row[$subfield];
}
array_multisort($sortarray, SORT_ASC, $array);
}
просто вызовите функцию, передав массив и имя поля массива второго уровня. Например:
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
был протестирован на 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*
}
вы можете попытаться определить свою собственную функцию сравнения, а затем использовать usort.
эта функция повторно используется:
function usortarr(&$array, $key, $callback = 'strnatcasecmp') {
uasort($array, function($a, $b) use($key, $callback) {
return call_user_func($callback, $a[$key], $b[$key]);
});
}
Он хорошо работает на строковые значения по умолчанию, но вы будете иметь, чтобы вложенные функции обратного вызова для функция сравнения если все значения являются числами.
С сортировка массива ассоциативных массивов по значению заданного ключа в 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");
//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
)
)
Полная Динамическая Функция Я прыгнул сюда для сортировки ассоциативного массива и нашел эту удивительную функцию наhttp://php.net/manual/en/function.sort.php. Эта функция очень динамична, что сортировка в порядке возрастания и убывания с указанным ключом.
простая функция для сортировки массива по определенным ключам. Поддерживает ассоциацию индексов
<?php
function array_sort($array, $on, $order=SORT_ASC)
{
$new_array = array();
$sortable_array = array();
if (count($array) > 0) {
foreach ($array as $k => $v) {
if (is_array($v)) {
foreach ($v as $k2 => $v2) {
if ($k2 == $on) {
$sortable_array[$k] = $v2;
}
}
} else {
$sortable_array[$k] = $v;
}
}
switch ($order) {
case SORT_ASC:
asort($sortable_array);
break;
case SORT_DESC:
arsort($sortable_array);
break;
}
foreach ($sortable_array as $k => $v) {
$new_array[$k] = $array[$k];
}
}
return $new_array;
}
$people = array(
12345 => array(
'id' => 12345,
'first_name' => 'Joe',
'surname' => 'Bloggs',
'age' => 23,
'sex' => 'm'
),
12346 => array(
'id' => 12346,
'first_name' => 'Adam',
'surname' => 'Smith',
'age' => 18,
'sex' => 'm'
),
12347 => array(
'id' => 12347,
'first_name' => 'Amy',
'surname' => 'Jones',
'age' => 21,
'sex' => 'f'
)
);
print_r(array_sort($people, 'age', SORT_DESC)); // Sort by oldest first
print_r(array_sort($people, 'surname', SORT_ASC)); // Sort by surname
$arr1 = array(
array('id'=>1,'name'=>'aA','cat'=>'cc'),
array('id'=>2,'name'=>'aa','cat'=>'dd'),
array('id'=>3,'name'=>'bb','cat'=>'cc'),
array('id'=>4,'name'=>'bb','cat'=>'dd')
);
$result1 = array_msort($arr1, array('name'=>SORT_DESC);
$result2 = array_msort($arr1, array('cat'=>SORT_ASC);
$result3 = array_msort($arr1, array('name'=>SORT_DESC, 'cat'=>SORT_ASC));
function array_msort($array, $cols)
{
$colarr = array();
foreach ($cols as $col => $order) {
$colarr[$col] = array();
foreach ($array as $k => $row) { $colarr[$col]['_'.$k] = strtolower($row[$col]); }
}
$eval = 'array_multisort(';
foreach ($cols as $col => $order) {
$eval .= '$colarr[\''.$col.'\'],'.$order.',';
}
$eval = substr($eval,0,-1).');';
eval($eval);
$ret = array();
foreach ($colarr as $col => $arr) {
foreach ($arr as $k => $v) {
$k = substr($k,1);
if (!isset($ret[$k])) $ret[$k] = $array[$k];
$ret[$k][$col] = $array[$k][$col];
}
}
return $ret;
}
<?php
$inventory = array(
array("type"=>"fruit", "price"=>3.50),
array("type"=>"milk", "price"=>2.90),
array("type"=>"pork", "price"=>5.43),
);
function myfunc($a,$b){
return strnatcmp($a['price'],$b['price']);
}
$result=usort ($inventory,"myfunc");?>
<pre><?php print_r(array_reverse($inventory)); ?></pre>
самое простое решение :)
выход есть
Array
(
[0] => Array
(
[type] => pork
[price] => 5.43
)
[1] => Array
(
[type] => fruit
[price] => 3.5
)
[2] => Array
(
[type] => milk
[price] => 2.9
)
)
попробуйте это:
asort($array_to_sort, SORT_NUMERIC);
для справки см. В этом: http://php.net/manual/en/function.asort.php
см. различные флаги сортировки здесь: http://www.php.net/manual/en/function.sort.php