按键对数组进行排序/分组



TL;博士

按键对数组进行排序/分组而不向数组添加另一个级别(由 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 的 9cc 选项大于 100cc 选项。

(为清楚起见,示例输出为(:

50cc 选项 1
50cc 选项 2
50cc 选项 3
50cc 选项 4
50cc 选项 5
100cc 选项 1

100cc 选项 2
100cc 选项 3
50cc 选项 6
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);

您可以将密钥格式化为 cc 的 3 位数字和选项的 2 位数字......

$options[sprintf('%03d%02d', $cc, $id)] = $someValue;

这应该给你钥匙0503110002.

然后使用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 => "酒吧" "数组键" => 501 ] 1 => 数组:3 [▼ 0 => "foo" 1 => "酒吧" "数组键" => 504 ] 2 => 数组:3 [▼ 0 => "foo" 1 => "酒吧" "数组键" => 5045 ] 3 => 数组:3 [▼ 0 => "foo" 1 => "酒吧" "数组键" => 1002 ] 4 => 数组:3 [▼ 0 => "foo" 1 => "酒吧" "数组键" => 10045 ] 5 => 数组:3 [▼ 0 => "foo" 1 => "酒吧" "数组键" => 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 解决方案,而不是按其键值对数组进行排序/分组。让我知道这个答案是否可以(如果是这样,将删除免责声明部分(与否。

感谢您的帮助:)

最新更新