按键对数组排序/分组

时间:2018-10-23 08:47:56

标签: php mysql arrays sorting ksort

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。因此,循环计数器传递9的50cc选项大于100cc选项。

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

  

50cc选项1
  50cc选项2
  50cc选项3
  50cc选项4
  50cc选项5
  100cc选项1
  100cc选项2
  100cc选项3
  50cc选件6
  50cc选项7

也许最初的问题是我如何创建密钥,但是我尝试将ksort与几个不同的标志一起使用以尝试实现我的目标,但是这些标志似乎都没有针对我的目标m之后:

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);

4 个答案:

答案 0 :(得分:2)

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

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

应该为您提供密钥0503110002

然后使用SORT_STRING强制其将它们按字符串排序(尽管它们也将按数字排序)

答案 1 :(得分:0)

如果您可以将其他密钥添加到数组中,则可以创建一个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 =>“栏”       “ arrayKey” => 501] 1 => array:3 [▼       0 =>“ foo”       1 =>“栏”       “ arrayKey” => 504] 2 => array:3 [▼       0 =>“ foo”       1 =>“栏”       “ arrayKey” => 5045] 3 => array:3 [▼       0 =>“ foo”       1 =>“栏”       “ arrayKey” => 1002] 4 => array:3 [▼       0 =>“ foo”       1 =>“栏”       “ arrayKey” => 10045] 5 => array:3 [▼       0 =>“ foo”       1 =>“栏”       “ arrayKey” => 1251]]

答案 2 :(得分:0)

在此示例中,使“仿形分隔符”成为不常见的模式,例如“ 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”作为分隔符直接在键上运行爆炸。

答案 3 :(得分:0)

我不确定这是否可以解决我自己的问题,因为它可以解决问题,但方式不同。本质上,我已将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解决方案,而不是按键值对数组进行排序/分组。让我知道这个答案是否可以(如果可以,将删除免责声明部分)。

感谢您的帮助:)