TL; DR
Сортировать / группировать массив по ключу без добавления другого уровня в массив (данные анализируются плагином jQuery)?
подробности
Я строю массив, чтобы вернуться к некоторым <select>
Элемент DOM.
Он принимает CC (размер двигателя) в качестве параметра и использует его в качестве ключа, проблема заключается в сортировке массива после.
Допустим, пользователь выбирает этот диапазон CC:
50, 100, 125
50 имеет 32 варианта
100 имеет 3 варианта
125 имеет 12 доступных вариантов
Мой текущий код проходит через CC, выполняет SQL, чтобы получить параметры, а использование счетчика цикла создает ключ, подобный следующему:
$options[$cc. $id] = $someValue;
Это работает, как и следовало ожидать, однако мой вывод показывает результаты не в том порядке, в котором я нуждаюсь (CC ASC
— так что все 50-е должны показать сначала, вместе).
Проблема в том, что
50 с 32 идет вверх
5031
в качестве ключа.
100 с 3 идет вверх1002
в качестве ключа.
125 с 12 идет вверх12511
в качестве ключа.
Надеюсь, теперь вы можете ясно увидеть проблему. 5031 больше, чем 1002. Таким образом, опции для 50cc с переданным счетчиком цикла 9 больше, чем 100cc.
(просто для ясности, пример вывода):
50cc Вариант 1
50cc Вариант 2
50cc Вариант 3
50cc Вариант 4
50cc Вариант 5
100cc Вариант 1
Вариант 100cc 2
Вариант 3 100cc
Вариант 6 объемом 50 куб.
50cc Вариант 7
Может быть, первоначальная проблема заключается в том, как я создаю ключи, но я пытался использовать ksort
с несколькими различными флагами, чтобы попытаться достичь моей цели, но ни один из флагов, кажется, не нацеливается на то, что я преследую:
SORT_REGULAR - compare items normally (don't change types) SORT_NUMERIC - compare items numerically SORT_STRING - compare items as strings SORT_LOCALE_STRING - compare items as strings, based on the current locale. It uses the locale, which can be changed using setlocale() SORT_NATURAL - compare items as strings using "natural ordering" like natsort() SORT_FLAG_CASE - can be combined (bitwise OR) with SORT_STRING or SORT_NATURAL to sort strings case-insensitively
Как отсортировать / сгруппировать ключи без добавления другого уровня в мой массив (данные анализируются с помощью плагина jQuery, который требует данные в определенном формате)?
РЕДАКТИРОВАТЬ: Полный скрипт
<?php
if (strpos(PHP_OS, 'Linux') > -1) {
require_once $_SERVER['DOCUMENT_ROOT']. '/app/connect.php';
} else {
require_once getcwd(). '\\..\\..\\..\\..\\app\\connect.php';
}
$make = $_POST['make'];
$cc = $_POST['cc'];
$sql = 'SELECT * FROM `table`
WHERE `UKM_CCM` = :cc
AND `UKM_Make` = :make
ORDER BY `UKM_Model`, `UKM_StreetName`, `Year` ASC;';
$options = array();
foreach ($cc as $k => $value)
{
$res = $handler->prepare($sql);
$res->execute(array(':cc' => $value, ':make' => $make));
$data = $res->fetchAll(PDO::FETCH_ASSOC);
$i = 0;
if (count($data) > 0) {
foreach ($data as $result)
{
$arrayKey = sprintf('%03d%02d', $cc, $i);
$epid = $result['ePID'];
$make = $result['UKM_Make'];
$model = $result['UKM_Model'];
$cc = $result['UKM_CCM'];
$year = $result['Year'];
$sub = $result['UKM_Submodel'];
$street = $result['UKM_StreetName'];
$options[$arrayKey]['name'] = $make. ' ' .$model. ' ' .$cc. ' ' .$year. ' ' .$sub. ' ' .$street;
$options[$arrayKey]['value'] = $epid;
$options[$arrayKey]['checked'] = false;
$options[$arrayKey]['attributes']['data-epid'] = $epid;
$options[$arrayKey]['attributes']['data-make'] = $make;
$options[$arrayKey]['attributes']['data-model'] = $model;
$options[$arrayKey]['attributes']['data-cc'] = $cc;
$options[$arrayKey]['attributes']['data-year'] = $year;
$options[$arrayKey]['attributes']['data-sub'] = $sub;
$options[$arrayKey]['attributes']['data-street'] = $street;
$i++;
}
}
}
ksort($options, SORT_STRING);
echo json_encode($options);
Вы можете отформатировать ключ, чтобы иметь 3 цифры для cc и 2 для опции …
$options[sprintf('%03d%02d', $cc, $id)] = $someValue;
который должен дать вам ключи 05031
а также 10002
,
Тогда используйте SORT_STRING
заставить его сортировать их как строки (хотя они будут сортировать и по числам)
Если вы можете добавить ключ дополнительно в свой массив, вы можете создать usort()
это отсортирует ваш массив так, как вам нужно:
$arrSort = [50, 100, 125];
$arrData = [
501 => [
'foo',
'bar',
'arrayKey' => 501
],
504 => [
'foo',
'bar',
'arrayKey' => 504
],
1002 => [
'foo',
'bar',
'arrayKey' => 1002
],
10045 => [
'foo',
'bar',
'arrayKey' => 10045
],
1251 => [
'foo',
'bar',
'arrayKey' => 1251
],
5045 => [
'foo',
'bar',
'arrayKey' => 5045
]
];
usort($arrData, function($a, $b) use ($arrSort)
{
$posA = array_search(substr($a['arrayKey'], 0, 2), $arrSort);
if ($posA === false) {
$posA = array_search(substr($a['arrayKey'], 0, 3), $arrSort);
}
$posB = array_search(substr($b['arrayKey'], 0, 2), $arrSort);
if ($posB === false) {
$posB = array_search(substr($b['arrayKey'], 0, 3), $arrSort);
}
return $posA - $posB;
});
Возвращение этой функции в этом примере будет:
массив: 6 [▼ 0 => массив: 3 [▼
0 => «foo» 1 => «bar» «arrayKey» => 501] 1 => array: 3 [▼
0 => «foo» 1 => «bar» «arrayKey» => 504] 2 => array: 3 [▼
0 => «foo» 1 => «bar» «arrayKey» => 5045] 3 => array: 3 [▼
0 => «foo» 1 => «bar» «arrayKey» => 1002] 4 => array: 3 [▼
0 => «foo» 1 => «bar» «arrayKey» => 10045] 5 => array: 3 [▼
0 => «foo» 1 => «bar» «arrayKey» => 1251]]
Сделайте ваш «искусственный разделитель» необычным шаблоном, как «929292» в этом примере. Тогда вы можете использовать uksort, чтобы пройти только ваши ключи. замените «929292» на «.» Таким образом, вы получите что-то вроде «100,3», «125,12» и «150,32».
Теперь вы больше не ограничены попытками работать численно и с шаблонами, вы можете использовать старый добрый разнесение и сравнивать вручную.
Это решение не заботится о том, что вложено в ваши массивы, оно касается только ключей для сортировки.
$options = [
'1009292923' => '100cc',
'12592929212' => '150cc',
'5092929232' => '50cc'
];
$sorted = uksort($options, function($a, $b){
$parts = explode('.',str_replace('929292', '.', $a));
$acc = $parts[0];
$parts = explode('.',str_replace('929292', '.', $b));
$bcc = $parts[0];
if($acc == $bcc) { return 0; }
if($acc > $bcc) { return 1; }
if($acc < $bcc) { return -1; }
});
var_dump($options);
Редактировать: Здесь str_replace вроде бессмысленен, вы можете просто запустить разнесение непосредственно по ключу, используя «929292» в качестве разделителя.
Я не уверен, что это может быть точным ответом на мой собственный вопрос, поскольку он решает проблему, но по-другому. По сути, я изменил свой SQL на это:
$sql = 'SELECT * FROM `ebay_mml`
WHERE `UKM_CCM` IN ('. $where .')
AND `UKM_Make` = :make
ORDER BY CAST(SUBSTR(`UKM_CCM`, INSTR(`UKM_CCM`, " ") + 1) AS UNSIGNED),
`UKM_Model`,
`UKM_StreetName`,
`Year`
ASC;';
$where
переменная, сгенерированная из цикла foreach:
foreach ($cc as $k => $v)
{
$where .= ':'. $k .($k != end(array_keys($cc)) ? ', ' : '');
$whereData[':'. $k] = $v;
}
Это возвращает все мои данные за раз, поэтому все, что мне нужно сделать сейчас, это просмотреть все результаты и подсчитать итерации, пока я собираюсь построить ключ:
$i = 0;
foreach ($data as $result)
{
# my sexy code
$i++;
}
Теперь мои результаты такие, как я хочу.
Отказ от ответственности: так как это действительно решает проблему, это как бы отклоняется от первоначального вопроса, поскольку это скорее решение MySQL, а не сортировка / группировка массива по значению его ключа. Дайте мне знать, если этот ответ в порядке (если так, удалит сегмент отказа от ответственности) или нет.
Спасибо всем за помощь 🙂