Sort array php kb, mb, gb

2

I have an array that filled with a query. What I get is the following:

array (size=9)
  '128 GB' => 
    array (size=1)
      0 => string '156' (length=3)
  '16 GB' => 
    array (size=2)
      0 => string '106' (length=3)
      1 => string '331' (length=3)
  '32 GB' => 
    array (size=2)
      0 => string '293' (length=3)
      1 => string '549' (length=3)
  '32 MB' => 
    array (size=2)
      0 => string '29' (length=2)
      1 => string '419' (length=3)
  '4 GB' => 
    array (size=2)
      0 => string '42' (length=2)
      1 => string '376' (length=3)
  '512 MB' => 
    array (size=1)
      0 => string '230' (length=3)
  '64 GB' => 
    array (size=1)
      0 => string '118' (length=3)
  '8 GB' => 
    array (size=2)
      0 => string '8' (length=1)
      1 => string '315' (length=3)
  '90 KB' => 
    array (size=1)
      0 => string '431' (length=3)

Then I print it in an HTML in input checkbox :

<?php foreach ($memories as $name => $ram ): ?>
  <li value="<?= implode(',', $ram) ?>">
  <input type="checkbox" name="checkboxG5" id="id_<?= $name ?>"/>
<label for="id_<?=  $name ?>" class="css-label radGroup2">
 <?= $name ?>
</label>
</li>
<?php endforeach; ?>

Everything works fine, the only drawback is that I want to order so that it does not leave 128gb , 16gb , 32gb ... I want to be able to order that for the value, instead of ordering alphabetically, order me by size.

    
asked by cignius 09.11.2016 в 20:26
source

4 answers

3

Why invent the wheel again and again? :)

In the notes contributed by the users of php.net - filesize () , there is two very nice features:

The first feature is filesize2bytes () , converts the file size, human-readable , in bytes.

Example: '10 MB' => 10000000

function filesize2bytes($str) { 

    $bytes = 0; 

    $bytes_array = array( 
        'B' => 1, 
        'KB' => 1024, 
        'MB' => 1024 * 1024, 
        'GB' => 1024 * 1024 * 1024, 
        'TB' => 1024 * 1024 * 1024 * 1024, 
        'PB' => 1024 * 1024 * 1024 * 1024 * 1024, 
    ); 

    $bytes = floatval($str); 

    if (preg_match('#([KMGTP]?B)$#si', $str, $matches) && !empty($bytes_array[$matches[1]])) { 
        $bytes *= $bytes_array[$matches[1]]; 
    } 

    $bytes = intval(round($bytes, 2)); 

    return $bytes; 
}

The second function is human_filesize () , converts bytes to file size, readable by humans.

Example: 10000000 => '10 MB'

function human_filesize($bytes, $decimals = 0) {

  $sz = 'BKMGTP';
  $factor = floor((strlen($bytes) - 1) / 3);

  return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) .' '. @$sz[$factor].'B';
}

Now you only need to combine the two functions and et voilà!

$sortMemory = [];
$newMemory  = [];

foreach($memory as $bytes => $value) {

    // guardamos todo en el mismo orden pero con bytes
    $sortMemory[filesize2bytes($bytes)] = $value;
}

// ordenamos el array por la clave
ksort($sortMemory);

foreach($sortMemory as $readable_size => $value) {

    // y guardamos el array ordenado pero con el tamaño del archivo legible
    $newMemory[human_filesize($readable_size)] = $value;
}

And already with your code, (little modified), you have your list sorted:

<?php

foreach ($newMemory as $name => $ram ):

    // crea una id_90_KB sin espacio !
    $name_ID = 'id_'.str_replace(' ', '_', $name);
?>

<li value="<?php echo implode(',', $ram) ?>">
  <input type="checkbox" name="checkboxG5" id="<?php echo $name_ID; ?>"/>
  <label for="<?php echo  $name_ID; ?>" class="css-label radGroup2"><?php echo $name; ?></label>
</li>

<?php endforeach; ?>

Result:

<li value="431">
  <input type="checkbox" name="checkboxG5" id="id_90_KB"/>
  <label for="id_90_KB" class="css-label radGroup2">90 KB</label>
</li>    

<li value="29,419">
  <input type="checkbox" name="checkboxG5" id="id_32_MB"/>
  <label for="id_32_MB" class="css-label radGroup2">32 MB</label>
</li>    

<li value="230">
  <input type="checkbox" name="checkboxG5" id="id_512_MB"/>
  <label for="id_512_MB" class="css-label radGroup2">512 MB</label>
</li>    

<li value="42,376">
  <input type="checkbox" name="checkboxG5" id="id_4_GB"/>
  <label for="id_4_GB" class="css-label radGroup2">4 GB</label>
</li>    

<li value="8,315">
  <input type="checkbox" name="checkboxG5" id="id_8_GB"/>
  <label for="id_8_GB" class="css-label radGroup2">8 GB</label>
</li>    

<li value="106,331">
  <input type="checkbox" name="checkboxG5" id="id_16_GB"/>
  <label for="id_16_GB" class="css-label radGroup2">16 GB</label>
</li>    

<li value="293,549">
  <input type="checkbox" name="checkboxG5" id="id_32_GB"/>
  <label for="id_32_GB" class="css-label radGroup2">32 GB</label>
</li>    

<li value="118">
  <input type="checkbox" name="checkboxG5" id="id_64_GB"/>
  <label for="id_64_GB" class="css-label radGroup2">64 GB</label>
</li>    

<li value="156">
  <input type="checkbox" name="checkboxG5" id="id_128_GB"/>
  <label for="id_128_GB" class="css-label radGroup2">128 GB</label>
</li>

View Demo

    
answered by 10.11.2016 / 01:00
source
1

Although PHP offers different functions to sort using keys ( ksort , krsort and uksort , you can see the complete list in the official PHP documentation ), none of them offer exactly what you are looking for because it does not allow you to specify your own comparison function, and those that could work use the value and in some cases you lose the key ( key ).

I'm afraid it's going to touch you to do something specific for your case. An alternative would be to create an array with the keys, sort that array (with some of PHP's native methods, such as usort ) and modify the code a bit later.

Here I leave you an option, what it does is that it transforms the value to bytes and then performs the comparison in a numerical way):

<?php

$memories = array(
    '128 GB' => array('156'),
    '16 GB' => array('106', '331'),
    '32 GB' => array('293','549'),
    '32 MB' => array('29', '419'),
    '4 GB' => array('42','376'),
    '512 MB' => array('230'),
    '64 GB' => array('118'),
    '8 GB' => array('8','315'),
    '90 KB' => array('431')
);

// creamos un array auxiliar que tendrá dos valores: la llave y el valor original
$memories2 = array();
foreach($memories as $name => $value) {
    $memories2[] = array($name, $value);
}

// función de comparación
function comparaSizes($a, $b) {

    // separamos el valor de la llave en arrays (0 => número; 1 => unidad)
    $arrA = explode(" ", $a[0]);
    $arrB = explode(" ", $b[0]);

    // calculamos el valor en Bytes para cada unidad
    switch ($arrA[1]) {
        case "GB": $arrA[0] = intval($arrA[0]) * 1000000000; break;
        case "MB": $arrA[0] = intval($arrA[0]) * 1000000; break;
        case "KB": $arrA[0] = intval($arrA[0]) * 1000; break;
        default: $arrA[0] = intval($arrA[0]);
    }

    // calculamos el valor en Bytes para cada unidad
    switch ($arrB[1]) {
        case "GB": $arrB[0] = intval($arrB[0]) * 1000000000; break;
        case "MB": $arrB[0] = intval($arrB[0]) * 1000000; break;
        case "KB": $arrB[0] = intval($arrB[0]) * 1000; break;
        default: $arrB[0] = intval($arrB[0]);
    }

    // devolvemos la comparación de los valores en Bytes
    return ($arrA[0] < $arrB[0]) ? -1 : 1;
}

// ordenas el array auxiliar usando la función de comparación que acabas de crear
usort($memories2, "comparaSizes");

// tu mismo código adaptándolo un poco
foreach ($memories2 as $name => $ram ): ?>
  <li value="<?= implode(',', $ram[1]) ?>">
  <input type="checkbox" name="checkboxG5" id="id_<?= $ram[0] ?>"/>
<label for="id_<?=  $ram[0] ?>" class="css-label radGroup2">
 <?= $ram[0] ?>
</label>
</li>
<?php endforeach; ?>

When I run that code, the result looks something like this:

[ ] 90 KB
[ ] 32 MB
[ ] 512 MB
[ ] 4 GB
[ ] 8 GB
[ ] 16 GB
[ ] 32 GB
[ ] 64 GB
[ ] 128 GB
    
answered by 09.11.2016 в 22:27
0

Try this, it should work, since it recreates the array in the same way

$memories=array(
    "32 GB"=>["293","456"],
    "128 GB"=>["500","600"],
    "4 GB"=>["800","700"]
);
var_dump($memories);
uksort($memories,'strnatcasecmp');
var_dump($memories);

The result

    
answered by 09.11.2016 в 22:40
0

It would be better if you could pass the sql query that you use and see if from there you can get the data in order using ORDER BY.

For example, you can place ORDER BY ram ASC

Ram as an example, you substitute it by the name of the field where you get those values (128gb, etc).

That should be the most effective solution since with just a few letters you would achieve your goal, without having to add more because the more you create it, the more difficult to maintain.

Tell me how!

    
answered by 10.11.2016 в 00:33