Reputation: 3758
This is what I currently have:
use Illuminate\Support\Collection;
$order = ['Land', 'Planeswalker', 'Creature', 'Instant', 'Sorcery', 'Enchantment', 'Artifact'];
$landOrder = ['Basic', ''];
$deck = $deck->sortBy(function($card) use ($landOrder) {
foreach ($landOrder as $index => $supertypes) {
if (str_contains($card->supertypes, $supertypes)) {
return $index;
}
}
})->values();
$deck = $deck->sortBy(function($card) use ($order) {
foreach ($order as $index => $type) {
if (str_contains($card->types, $type)) {
return $index;
}
}
})->values();
Basically I'd like to sort by $order first and then tweak the order based on $landOrder.
Currently it sorts by whichever function was executed second. How can I make it so it sorts for both?
Upvotes: 1
Views: 403
Reputation: 62228
I would use the sort
method instead of sortBy
. The sort
method uses the PHP uasort
function, which gives you a little more control over the sorting functionality.
$deck->sort(function($a, $b) use ($order, $landOrder) {
// get the order indexes for the two items
$ai = array_search($a->types, $order);
$bi = array_search($b->types, $order);
// if the two items have the same order, drill down to the land order comparison
if ($ai === $bi) {
// get the land order indexes for the two items
$aii = array_search($a->supertypes, $landOrder);
$bii = array_search($b->supertypes, $landOrder);
// order based on "natural order" comparison of land order indexes
return strnatcmp($aii, $bii);
}
// order based on "natural order" comparison of order indexes
return strnatcmp($ai, $bi);
})->values();
You'll need to update the function to implement whatever logic is needed to get the correct index from the $order
and $landOrder
arrays. I just used array_search()
as a quick and easy function, but this assumes that the value of the types
and supertypes
attributes would be exact matches to the entries in the arrays (i.e. 'Land' and 'Basic', not '["Land"]' and '["Basic"]').
Based on the logic from your question, and the format of the attributes from your comments, you're probably looking for something like this:
$deck->sort(function($a, $b) use ($order, $landOrder) {
// get the order indexes for the two items
$ai = null;
$bi = null;
foreach ($order as $index => $type) {
if (str_contains($a->types, $type)) {
$ai = $index;
}
if (str_contains($b->types, $type)) {
$bi = $index;
}
}
// if the type is not in the array, assign some type of value that will order like types together, but after all other proper types
if (is_null($ai)) {
$ai = count($order).$a->types;
}
if (is_null($bi)) {
$bi = count($order).$b->types;
}
// if the two items have the same order, drill down to the land order comparison
if ($ai === $bi) {
// get the land order indexes for the two items
$aii = null;
$bii = null;
foreach ($landOrder as $index => $supertype) {
if (str_contains($a->supertypes, $supertype)) {
$aii = $index;
}
if (str_contains($b->supertypes, $supertype)) {
$bii = $index;
}
}
// if the supertype is not in the array, assign some type of value that will order like supertypes together, but after all other proper supertypes
if (is_null($aii)) {
$aii = count($landOrder).$a->supertypes;
}
if (is_null($bii)) {
$bii = count($landOrder).$b->supertypes;
}
// order based on "natural order" comparison of land order indexes
return strnatcmp($aii, $bii);
}
// order based on "natural order" comparison of order indexes
return strnatcmp($ai, $bi);
})->values();
Upvotes: 1