Как отсортировать многомерный массив по значениям нескольких ключей, строк и целых чисел

У меня есть множество людей (законодателей), перечисляющих их уровень, штат, палату и район. Я хотел бы отсортировать массив на основе значений этих 4 ключей, но в произвольном порядке, поскольку некоторые из этих значений являются строками. Например, я бы хотел сначала отсортировать по «уровню» по порядку («федеральный», «штат», затем что-нибудь еще), затем указать штат в алфавитном порядке по возрастанию, затем по камере («губернатор», «верхний»). «ниже», затем все остальное), затем район в порядке возрастания номеров. Вот сокращенный пример массива, который я использую.

Array
(
[0] => stdClass Object
(
[district] => 15
[state] => fl
[level] => state
[chamber] => upper

)

[1] => stdClass Object
(
[district] => 50
[state] => fl
[level] => state
[chamber] => lower
)
[2] => stdClass Object
(
[district] => 0
[state] => fl
[level] => state
[chamber] => governor

)
)

-1

Решение

Решение @ BusyBeaver cmp()/compare() Функция довольно сложна и ее сложно обновить, если вы хотите изменить порядок или, не дай Бог, добавить другое поле!

это было то, что я придумал:

<?php
function sortValue($key, $value)
{
static $arrValueOrder = [
'level' => ['federal', 'state'],
'chamber' => ['governor', 'upper', 'lower']
];

if (array_key_exists($key, $arrValueOrder)) {
if (($result = array_search($value, $arrValueOrder[$key])) === false) {
$result = count($arrValueOrder[$key]);
}
} else {
$result = $value;
}
return $result;
}

function cmp($a, $b)
{
static $arrFieldOrder = ['level', 'state', 'chamber', 'district'];

$result = 0;
reset($arrFieldOrder);
while ($result === 0 && list($key, $value) = each($arrFieldOrder)) {
$aSortValue = sortValue($value, $a->$value);
$bSortValue = sortValue($value, $b->$value);
if ($aSortValue > $bSortValue) {
$result = 1;
} elseif ($aSortValue < $bSortValue) {
$result = -1;
}
}
return $result;
}

// setup some test data
$arrData = [
(object)['district' => 15, 'state' => 'fl', 'level' => 'state', 'chamber' => 'upper'],
(object)['district' => 15, 'state' => 'tx', 'level' => 'federal', 'chamber' => 'lower'],
(object)['district' => 50, 'state' => 'fl', 'level' => 'state', 'chamber' => 'lower'],
(object)['district' => 15, 'state' => 'tx', 'level' => 'federal', 'chamber' => 'upper'],
(object)['district' => 0, 'state' => 'fl', 'level' => 'state', 'chamber' => 'governor'],
(object)['district' => 15, 'state' => 'tx', 'level' => 'federal', 'chamber' => 'governor'],
(object)['district' => 15, 'state' => 'tx', 'level' => 'federal', 'chamber' => 'foo'],
(object)['district' => 15, 'state' => 'fl', 'level' => 'federal', 'chamber' => 'upper']
];

// sort it
usort($arrData, 'cmp');

// dump the result
var_dump($arrData);
2

Другие решения

usort() может решить вашу проблему, вам нужно только написать хорошую функцию сравнения, которая работает как вам нужно.

<?php

$lawmakers = ... // Your lawmakers array.
usort($lawmakers, "cmp");

// returns 0 if equal; -1 if $a < $b; 1 otherwise
function cmp($a, $b) {
// 1. Compare level: "federal" < "state" < anything else
if ($a["level"] === "federal" && $b["level"] !== "federal") return -1;
else if ($a["level"] !== "federal" && $b["level"] === "federal") return 1;
else if ($a["level"] === "state" && $b["level"] !== "state") return -1;
else if ($a["level"] !== "state" && $b["level"] === "state") return 1;
// 2. Compare state: alphabetical order
if (strcmp($a["state"], $b["state"]) > 0) return 1;
else if (strcmp($a["state"], $b["state"]) < 0) return -1;
// 3. Compare chamber: "governor" < "upper" < "lower" < anything else
if ($a["chamber"] === "governor" && $b["chamber"] !== "governor") return -1;
else if ($a["chamber"] !== "governor" && $b["chamber"] === "governor") return 1;
else if ($a["chamber"] === "upper" && $b["chamber"] !== "upper") return -1;
else if ($a["chamber"] !== "upper" && $b["chamber"] === "upper") return 1;
else if ($a["chamber"] === "lower" && $b["chamber"] !== "lower") return -1;
else if ($a["chamber"] !== "lower" && $b["chamber"] === "lower") return 1;
// 4. Compare district: ascending
if ($a["district"] < $b["district"]) return -1;
else if ($a["district"] > $b["district"]) return 1;
// 5. If we came so far... $a and $b are equals
return 0;
}
?>

Вы также можете подумать об объектно-ориентированном решении (которое все еще нуждается в функции сравнения …)

<?php

// Testing
$a = new Lawmaker("federal", "fl", "upper", 15);
$b = new Lawmaker("state", "fl", "lower", 7);
$c = new Lawmaker("federal", "fl", "upper", 8);
$d = new Lawmaker("other", "wy", "governor", 1);
$lawmakers = Array($a, $b, $c, $d);
mysort($lawmakers);
print_r($lawmakers);// Class Lawmaker to define Lawmaker object
class Lawmaker
{
// Properties declaration
public $level;
public $state;
public $chamber;
public $district;

// Lawmaker constructor
function __construct($level, $state, $chamber, $district) {
$this->level = $level;
$this->state = $state;
$this->chamber = $chamber;
$this->district = $district;
}

// Compare $this Lawmaker with $other Lawmaker
// returns 0 if equal; -1 if $this < $other; 1 otherwise
public function compare($other) {
// 1. Compare level: "federal" < "state" < anything else
if ($this->level === "federal" && $other->level !== "federal") return -1;
else if ($this->level !== "federal" && $other->level === "federal") return 1;
else if ($this->level === "state" && $other->level !== "state") return -1;
else if ($this->level !== "state" && $other->level === "state") return 1;
// 2. Compare state: alphabetical order
if (strcmp($this->state, $other->state) > 0) return 1;
else if (strcmp($this->state, $other->state) < 0) return -1;
// 3. Compare chamber: "governor" < "upper" < "lower" < anything else
if ($this->chamber === "governor" && $other->chamber !== "governor") return -1;
else if ($this->chamber !== "governor" && $other->chamber === "governor") return 1;
else if ($this->chamber === "upper" && $other->chamber !== "upper") return -1;
else if ($this->chamber !== "upper" && $other->chamber === "upper") return 1;
else if ($this->chamber === "lower" && $other->chamber !== "lower") return -1;
else if ($this->chamber !== "lower" && $other->chamber === "lower") return 1;
// 4. Compare district: ascending
if ($this->district < $other->district) return -1;
else if ($this->district > $other->district) return 1;
// 5. If we came so far... $this and $other are equals
return 0;
}
}

function mysort(&$array) {
// Simple selection sort. You can implement any sorting algorithm.
for ($i = 0; $i < count($array); $i++) {
$pos = $i;
// Search for minimum
for ($j = $i+1; $j < count($array); $j++) {
if ($array[$j]->compare($array[$pos]) < 0) {
$pos = $j;
}
}
// Swap
$temp = $array[$i];
$array[$i] = $array[$pos];
$array[$pos] = $temp;
}
// Done.
}
1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector