Как отсортировать многомерный массив по двум значениям с помощью оператора космического корабля?
Я пытаюсь отсортировать многомерный массив с помощью оператора космического корабля.
<?php
$my_array = [
['name'=>'cool', 'volume'=> 2, 'page'=>1],
['name'=>'sonic', 'volume'=> 1, 'page'=>1],
['name'=>'tails', 'volume'=> 3, 'page'=>1],
['name'=>'knuckles', 'volume'=> 1, 'page'=>2],
['name'=>'amy', 'volume'=> 1, 'page'=>3],
['name'=>'charmy', 'volume'=> 0, 'page'=>1]
];
usort($my_array, function ($a, $b) {
return $a['page'] <=> $b['page'];
});
var_dump($my_array);
Я могу сделать только с одним значением для сравнения, однако, как сортировать, используя два значения (объем и страница)?
4 ответа
Не ответ на ваш вопрос, но я обычно делаю несколько значений следующим образом:
array_multisort(array_column($my_array, 'page'),
array_column($my_array, 'volume'), SORT_DESC, $my_array);
<?php
$my_array = [
['name'=>'cool', 'volume'=> 2, 'page'=>1],
['name'=>'cool', 'volume'=> 1, 'page'=>1],
['name'=>'cool', 'volume'=> 3, 'page'=>1],
['name'=>'cool', 'volume'=> 1, 'page'=>2],
['name'=>'cool', 'volume'=> 1, 'page'=>3],
['name'=>'cool', 'volume'=> 0, 'page'=>1]
];
usort($my_array, function ($a, $b) {
$page = $a['page'] <=> $b['page'];
$volume = $a['volume'] <=> $b['volume'];
if(0 == $page){
return $volume;
}else{
return $page;
}
});
var_dump($my_array);
Если usort()
это необходимо, то вы можете сделать это так:
<?php
$my_array = [
['name'=>'cool', 'volume'=> 2, 'page'=>1],
['name'=>'cool', 'volume'=> 1, 'page'=>1],
['name'=>'cool', 'volume'=> 3, 'page'=>1],
['name'=>'cool', 'volume'=> 1, 'page'=>2],
['name'=>'cool', 'volume'=> 1, 'page'=>3],
['name'=>'cool', 'volume'=> 0, 'page'=>1]
];
usort($my_array, function ($a, $b) {
$return = $a['page'] <=> $b['page'];
return ( !$return ? $a['volume'] <=> $b['volume'] : $return );
});
var_dump($my_array);
Я не проверял это, и вы не предоставили образец желаемого результата, поэтому вам может потребоваться изменить его в соответствии с вашими потребностями.
https://www.the-art-of-web.com/php/sortarray/ содержит множество отличных сортировочных материалов.
Интересный способ представить функциональное программирование -
# main.php
require 'comparison.php';
function sortByPage ($a, $b) {
return $a['page'] <=> $b['page'];
}
function sortByVolume ($a, $b) {
return $a['volume'] <=> $b['volume'];
}
// first sort by volume, then sort by page
usort($my_array, \comparison\concat (sortByVolume, sortByPage));
Выше concat
может быть не сразу интуитивно понятным. Конечно, вы concat
две строки или два массива, и вы даже можете подумать о добавлении чисел, таких как 1 + 2, как concat (1, 2)
, Но как это выглядит concat
две функции?
Когда ты concat
две строки, результатом является строка. Когда ты concat
два массива, результатом является массив. Когда ты concat
две функции сравнения, результатом будет другая функция сравнения.
# comparison.php
namespace comparison;
require 'ordered.php';
function concat ($c1, $c2) {
return function ($a, $b) use ($c1, $c2) {
return \ordered\concat
( $c1 ($a, $b)
, $c2 ($a, $b)
);
};
}
Функция сравнения принимает два аргумента и должна возвращать упорядоченный результат (-1, 0 или 1). Но так же, как мы можем реализовать concat
для функций сравнения мы также можем реализовать concat
для упорядоченных результатов. Итак, мы проходим $a
а также $b
для каждой функции сравнения, $c1
а также $c1
, каждый из которых приводит к упорядоченному значению. Окончательный результат concat
из двух упорядоченных значений.
Так что же происходит, когда ты concat
два упорядоченных значения? Вы получаете другое заказанное значение!
// ordered.php
namespace ordered;
function concat ($a, $b) {
return $a === 0 ? $b : $a;
}
Выше это все, что вам нужно для достижения желаемого результата, но некоторые решения могут показаться произвольными. Может быть, вы также чувствовали, что это было утомительно, чтобы определить sortByPage
а также sortByVolume
как отдельные функции. Может быть, вам нужна возможность обратной сортировки, и это будет означать определение еще большего количества функций. Или, может быть, вам нужно сортировать, используя более двух функций сортировки. Расширение нашего comparison
а также ordered
модули помогут.
ordered.php
PHP традиционно использует -1, 0 и 1 для кодирования упорядоченного результата. Мы можем быть более явными об этом в нашем модуле. Обратите внимание, что каждая функция проста, как и одна или две вещи.
namespace ordered;
const eq = 0;
const gt = 1;
const lt = -1;
function concat ($a, $b) {
return $a === eq ? $b : $a;
}
function sum ($os) {
return array_reduce ($os, '\ordered\concat', eq);
}
function reverse ($a) {
return $a * -1;
}
comparison.php
В этом модуле мы реализуем <=>
как функция compare
вместо оператора. Обратите внимание, мы также вернули заказанный lt
, gt
, или же eq
вместо -1, 1 или 0. Это учитывает барьер абстракции и позволяет упорядоченному модулю изменять свое представление, не затрагивая модуль сравнения. Еще раз подчеркиваем, что каждая функция выполняет только одну или две вещи.
namespace comparison;
require 'ordered.php';
function compare ($a, $b) {
if ($a < $b)
return \ordered\lt; // respect abstraction barrier
if ($a > $b)
return \ordered\gt; // respect abstraction barrier
else
return \ordered\eq; // respect abstraction barrier
}
function concat ($c1, $c2) {
return function ($a, $b) use ($c1, $c2) {
return \ordered\concat // respect abstraction barrier
( $c1 ($a, $b)
, $c2 ($a, $b)
);
};
}
function sum ($cs) {
return array_reduce ($cs, '\comparison\concat', '\comparison\compare');
}
function reverse ($c) {
return function ($a, $b) use ($c) {
return \ordered\reverse ($c ($a, $b)); // respect abstraction barrier
};
}
function contramap ($f, $g) {
return function ($a, $b) use ($f, $g) {
return $f
( $g ($a)
, $g ($b)
);
};
}
Эти простые модули подходят практически для любой задачи сортировки.
1. Объедините любое количество сортировщиков
// possibly based on form submission data
$sorters =
[ 'sortByVolume' // pre-defined function
, 'sortByPage' // pre-defined function
, 'sortByName' // pre-defined function
];
usort ($my_array, \comparison\sum ($sorters));
2. Обратная сортировка
usort ($my_array, \comparison\reverse ('sortByVolume'));
3. Анонимные сортировщики - не нужно определять sortByVolume
, sortByPage
, так далее.
function sortBy ($key) {
return \comparison\contramap
( '\comparison\compare'
, function ($x) use ($key) { return $x[$key]; }
);
}
usort
( $my_array
, \comparison\concat
( sortBy ('volume') // sorter created ad hoc
, sortBy ('page') // same here
)
);
4. Способность смешивать и сопоставлять эти эффекты и давать надежный результат является неоспоримым преимуществом функционального программирования.
$sorters =
[ 'sortByVolume', // pre-defined function
, sortBy ('page') // anonymous sorter
, reverse (sortBy ('name')) // reverse sorter
];
usort
( $my_array
, \comparison\sum ($sorters) // combine all sorters
);
В конце концов, мы не использовали оператор космического корабля <=>
в наших модулях. Функциональное программирование - это программирование с помощью функций, поэтому такие вещи, как операторы, ключевые слова и операторы, избегают использования простых функций. Причина этого в том, что функции могут быть легко объединены с использованием композиции, тогда как операторы и операторы не всегда могут быть объединены.