Я пытаюсь отсортировать многомерный массив с помощью оператора космического корабля.
<?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);
Я могу сделать только с одним значением для сравнения, однако, как сортировать с помощью два значения (объем и страница)?
Если 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/#section_3 есть много отличных сортировок.
Не ответ на ваш вопрос, но я обычно делаю несколько значений следующим образом:
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);
Интересный способ представить функциональное программирование —
# 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
);
В конце концов, мы не использовали оператор космического корабля <=>
в наших модулях. Функциональное программирование — это программирование с использованием функций, поэтому такие вещи, как операторы, ключевые слова и операторы, избегают использования простых функций. Причина этого в том, что функции могут быть легко объединены с использованием композиции, тогда как операторы и операторы не всегда могут быть объединены.