0

I have the following output values from a associative array (id => value):

1GB - 4GB
1TB - 2TB
3TB - 5TB
5GB - 16GB
6TB+
17GB - 32GB
33GB - 63GB
64GB - 120GB
121GB - 200GB
201GB - 300GB
301GB - 500GB
501GB - 1TB

How can I group and sort it so that I get it goes from smallest to largest:

so:

1GB - 4GB
5GB - 16GB
17GB - 32GB
33GB - 63GB
64GB - 120GB
121GB - 200GB
201GB - 300GB
301GB - 500GB
501GB - 1TB
1TB - 2TB
3TB - 5TB
6TB+
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Keezy
  • 293
  • 4
  • 15
  • Possible duplicate of [How can I sort arrays and data in PHP?](http://stackoverflow.com/questions/17364127/how-can-i-sort-arrays-and-data-in-php) – Shannon Jan 12 '16 at 02:45
  • 1
    Does the data come from a table? If so, you can add a column called "weight" then when you fetch the results you can add `ORDER BY weight DESC` or something similar to the end of the query. – Clay Jan 12 '16 at 02:59
  • @Dagon hey I'm trying to be lazy darn it lol, I just don't want to have to rearrange it everytime something changes. I have a few other similar arrays I wanted to use it on as well. – Keezy Jan 12 '16 at 03:09
  • 1
    @Clayton 6 that's actually not a bad idea. I like. – Keezy Jan 12 '16 at 03:09

3 Answers3

1

Posting my comment as an answer for posterity...

When you have strings that cannot be easily sorted and you are fetching the data from a database table, you can:

  1. Add a column called weight to the table that is of data type integer

  2. In the weight column use higher or lower numbers depending on how you want the data sorted.

  3. When querying the data add ORDER BY weight DESC to your query to fetch the results in the way you want it

Clay
  • 4,700
  • 3
  • 33
  • 49
0

If data not come from table, you may try this.

$arr = [
    '8TB' => '8TB',
    '1GB' => '4GB',
     '1TB' => '2TB',
     '3TB' => '5TB',
     '5GB' => '16GB',
     '17GB' => '32GB',
     '33GB' => '63GB',
     '64GB' => '120GB',
    ];

foreach($arr as $key => $val){
    $unit = strtoupper(trim(substr($key, -2)));
    $io[$unit][$key] = $val; 
}

function cmpValue($a, $b){
    return (substr($a, 0, -2) > substr($b, 0, -2)) ? true :false;
}

$sd = array_map(function($ele){
   uksort($ele, 'cmpValue');
   return $ele;
}, $io);


function cmpUnit($a, $b){
    $units = array('B'=>0, 'KB'=>1, 'MB'=>2, 'GB'=>3, 'TB'=>4,    'PB'=>5, 'EB'=>6, 'ZB'=>7, 'YB'=>8);
  return $units[$a] > $units[$b];
}

uksort($sd, 'cmpUnit');
$sordArray =  call_user_func_array('array_merge', $sd);
print_r($sordArray);
ampi89
  • 69
  • 7
0

While a larger set of units may need to work in conjunction with a lookup map of values relating to different unit abbreviations, this question is only dealing with GB and TB which will simply sort alphabetically.

For best efficiency, perform a single loop over the input values and parse the leading number and its trailing unit expression. The remainder of the strings appear to be irrelevant to accurate sorting.

Now that you have flat arrays to sort with, pass the units then the numbers into array_multisort(), then write the original array as the third parameter so that it is the "affected" array.

See also this related answer to a very similar question: PHP: Sort an array of bytes

Code: (Demo)

$nums = [];
$units = [];
foreach ($array as $v) {
    [$nums[], $units[]] = sscanf($v, '%d%[A-Z]');
}
array_multisort($units, $nums, $array);
var_export($array);

If the input is:

$array = [
    'a' => '1GB - 4GB',
    'b' => '1TB - 2TB',
    'c' => '3TB - 5TB',
    'd' => '5GB - 16GB',
    'e' => '6TB+',
    'f' => '17GB - 32GB',
    'g' => '33GB - 63GB',
    'h' => '64GB - 120GB',
    'i' => '121GB - 200GB',
    'j' => '201GB - 300GB',
    'k' => '301GB - 500GB',
    'l' => '501GB - 1TB',
];

The output is:

array (
  'a' => '1GB - 4GB',
  'd' => '5GB - 16GB',
  'f' => '17GB - 32GB',
  'g' => '33GB - 63GB',
  'h' => '64GB - 120GB',
  'i' => '121GB - 200GB',
  'j' => '201GB - 300GB',
  'k' => '301GB - 500GB',
  'l' => '501GB - 1TB',
  'b' => '1TB - 2TB',
  'c' => '3TB - 5TB',
  'e' => '6TB+',
)
mickmackusa
  • 43,625
  • 12
  • 83
  • 136