0

How can I sort some data in ascending order?

I've looped over several products to grab this (it should be noted that these could change to any number), here's the unsorted data:

  • 10mg
  • 100mg
  • 500mg
  • 1 gram
  • 30mg
  • 300mg
  • 1.5 gram
  • 3 gram

This is what I've tried but it doesn't output anything:

<select>
<?php $uniquePids = array_unique($results);
$results = sort($uniquePids);   
foreach ( $results as $result ) { ?>
    <option value="<?php echo $result; ?>"><?php echo $result; ?></option>
<?php } ?>
</select>

How can I sort it to be 10mg, 30mg, 100mg etc

Rob
  • 6,304
  • 24
  • 83
  • 189
  • why not explode on the spaces and arrange the ints that way? then just concat the right measurement – treyBake Aug 21 '17 at 16:04
  • you must sort your array with `uasort` and mapping the unit first and then the number – Sysix Aug 21 '17 at 16:04
  • 1
    `sort()` returns a boolean, not the sorted array. The array is passed as a reference, so you're currently overwriting your `$results` array with a boolean. [Read the manual on how to use sort()](http://php.net/manual/en/function.sort.php). If you check your error log, you should have an error since you're trying to iterate a boolean with foreach. – M. Eriksson Aug 21 '17 at 16:04
  • 1
    what about multiplying the gram items by 1000 (to get mg) then sorting and then converting those that are over 1000 back to mg? – Robert Sinclair Aug 21 '17 at 16:05
  • You may want to take a look at [usort](http://php.net/manual/en/function.usort.php). – Nathan Arthur Aug 21 '17 at 16:08
  • 1
    @MagnusEriksson has it right, but just out of curiosity, how can you tell if it's sorted properly if it doesn't output anything? – Don't Panic Aug 21 '17 at 16:45

2 Answers2

3

I think it's most beautiful solution: normalise to smallest units, count conversions factor, and sort by keys.

<?php

$a = [
    '10mg',
    '100mg',
    '500mg',
    '1 gram',
    '30mg',
    '300mg',
    '1.5 gram',
    '3 gram',
];


$r = [];

foreach ($a as $v) {

    if (strpos($v, 'mg') !== false) {$k = 1;} // 1 mg
    if (strpos($v, 'gram') !== false) {$k = 1000;} // 1 gram = 1000 mg

    $r[floatval($v)*$k] = $v;
}
ksort($r);
var_dump($r);

?>

array(8) {
  [10]=>
  string(4) "10mg"
  [30]=>
  string(4) "30mg"
  [100]=>
  string(5) "100mg"
  [300]=>
  string(5) "300mg"
  [500]=>
  string(5) "500mg"
  [1000]=>
  string(6) "1 gram"
  [1500]=>
  string(8) "1.5 gram"
  [3000]=>
  string(6) "3 gram"
}
Oleg
  • 109
  • 4
0

a bit complicated but it will also do kg! :-S

<select>
<?php
/**
 * convert string weight to milligrams
 *
 * @param string $value
 * @return float|int|false
 */
function strToMg($value)
{
    $result = false;
    if (preg_match('/^([0-9.]+)[ ]*g(ram)?s?$/', $value, $arrMatches)) {
        $result = $arrMatches[1] * 1000;
    } elseif (preg_match('/^([0-9.]+)[ ]*m(illi)?g(ram)?s?$/', $value, $arrMatches)) {
        $result = $arrMatches[1];
    } elseif (preg_match('/^([0-9.]+)[ ]*k(ilo)?g(ram)?s?$/', $value, $arrMatches)) {
        $result = $arrMatches[1] * 10000000;
    }
    return $result;
}

/**
 * compare 2 string weights
 *
 * @param string $a
 * @param string $b
 * @return int
 */
function cmp($a, $b)
{
    $aMg = strToMg($a);
    $bMg = strToMg($b);

    if ($aMg > $bMg) {
        $result = 1;
    } elseif ($aMg < $bMg) {
        $result = -1;
    } else {
        $result = 0;
    }
    return $result;
}

usort($results, 'cmp');
foreach ($results as $result) { ?>
    <option value="<?php echo $result; ?>"><?php echo $result; ?></option>
<?php } ?>
</select>
Wee Zel
  • 1,294
  • 9
  • 11