Сортировать / группировать массив по ключу - PullRequest
0 голосов
/ 23 октября 2018

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 Вариант 150cc Вариант 250cc Вариант 350cc Вариант 450cc Вариант 5100cc Вариант 1Вариант 100cc 2Вариант 3 100cc50cc Вариант 650cc Опция 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);

Ответы [ 4 ]

0 голосов
/ 23 октября 2018

Я не уверен, что это мог бы быть точный ответ на мой собственный вопрос, поскольку он решает проблему, но по-другому.По сути, я изменил свой 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, а не сортировка / группировка массива по значению его ключа.Дайте мне знать, если этот ответ в порядке (если так, удалит сегмент отказа от ответственности) или нет.

Спасибо за вашу помощь всем:)

0 голосов
/ 23 октября 2018

Если вы можете добавить дополнительный ключ в ваш массив, вы можете создать 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 => массив: 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 => массив: 3 [▼ 0 => "foo" 1 => "bar" "arrayKey" => 1251]]

0 голосов
/ 23 октября 2018

Сделайте ваш «искусственный разделитель» необычным шаблоном, как «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);

Edit: str_replace здесь бессмысленно, вы можете просто запустить разнесение непосредственно на ключе, используя "929292" в качестве разделителя.

0 голосов
/ 23 октября 2018

Вы можете отформатировать ключ, чтобы иметь 3 цифры для cc и 2 для опции ...

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

, которая должна давать вам ключи 05031 и 10002.

Затем используйте SORT_STRING, чтобы заставить его сортировать их как строки (хотя они также будут сортировать и по числам)

...