1

How might I sort the following using PHP? (where wed_2_open comes after wed_1_close)

I have the following JSON data:

"hours": {
  "mon_1_open": 406800,
  "mon_1_close": 437400,
  "tue_1_open": 493200,
  "tue_1_close": 523800,
  "wed_1_open": 579600,
  "wed_1_close": 590400,
  "thu_1_open": 61200,
  "thu_1_close": 91800,
  "fri_1_open": 147600,
  "fri_1_close": 178200,
  "sat_1_open": 237600,
  "sat_1_close": 264600,
  "sun_1_open": 324000,
  "sun_1_close": 345600,
  "wed_2_open": 597600,
  "wed_2_close": 619200
}

Which I then turn into a usable format using JSON_decode:

$obj=json_decode($json);

This is put into a loop to use convert it to HTML:

foreach ($obj->hours as $key => $val) {
    // Turn array items into HTML list items
}

From previous answers it seems like usort may be an answer, but I get errors telling me $obj is an object rather than an array.

Thanks.

1
  • 1
    json_decode($json, true) to force it as an associative array. by default it returns a stdClass object Commented Jun 14, 2011 at 9:22

3 Answers 3

4

Few notes:

  1. To use any of the array functions on the json_decode()ed data, you must pass true as the second parameter which gives you an associative array instead of an object.

  2. Whenever you plan to sort an array, look at this page which helps you decide which of the 12+ array sorting functions you should use.

Since the desired sorting is not intuitive (sorting by key puts friday on top and close before open) you should define a custom sorting function; use uksort() which allows you to do just that on array keys:

<?php
$data = json_decode('{"hours": {
    "mon_1_open": 406800,
    "mon_1_close": 437400,
    "tue_1_open": 493200,
    "tue_1_close": 523800,
    "wed_1_open": 579600,
    "wed_1_close": 590400,
    "thu_1_open": 61200,
    "thu_1_close": 91800,
    "fri_1_open": 147600,
    "fri_1_close": 178200,
    "sat_1_open": 237600,
    "sat_1_close": 264600,
    "sun_1_open": 324000,
    "sun_1_close": 345600,
    "wed_2_open": 597600,
    "wed_2_close": 619200
}}', true);

echo 'BEFORE ================================' . PHP_EOL;
print_r($data);

uksort($data['hours'], 'customsort'); 

echo 'AFTER  ================================' . PHP_EOL;
print_r($data);

function customsort($a, $b) {
    $tr_prefix = array(
        'mon' => 1,
        'tue' => 2,
        'wed' => 3,
        'thu' => 4,
        'fri' => 5,
        'sat' => 6,
        'sun' => 7
    );
    $tr_suffix = array(
        'open'  => 1,
        'close' => 2
    );
    $a = strtr(strtr($a, $tr_prefix), $tr_suffix);
    $b = strtr(strtr($b, $tr_prefix), $tr_suffix);
    return strcmp($a, $b);
}

Note: my customsort implementation shown above is vary naive. Improvise if necessary.

Sign up to request clarification or add additional context in comments.

1 Comment

Whilst the other posts were helpful, this one best identified the issue, which was the sorting of the days of the week. Combined with jond3k's answer, I have now got this working nicely.
3
$array = $json_decode($json,true);  //> tradyblix
ksort($array);                      //> Sort by keys

2 Comments

Using TRUE then breaks my foreach ($obj->hours as $key => $val) function as an invalid argument. How do I get around that? I guess using TRUE affects the need to use as $key => $val?
@Joe: try foreach($obj['hours'] as ...).
2

First off, your json is invalid as you're not placing curly brackets around the associative array that contains 'hours'. This might not be an issue if you've cut it out for brevity, but I had to change it when debugging.

More importantly, you can ask json_decode to convert the data in to an associative array instead of an instance of stdClass. ksort will then allow you to sort by keys.

$json = file_get_contents('jsonsort.txt');
$obj = json_decode($json, true);

var_dump($obj);
ksort($obj['hours']);
var_dump($obj);

You could have sorted by values with sort - usort is not needed unless you need to make a custom comparison function, say, comparing instances of objects.

You can then iterate and emit with this (escaping & markup added):

echo "<ol>\n";
foreach($obj['hours'] as $key => $val) {
        echo "\t<li>" . htmlentities($key) . ' => ' . htmlentities($val) . "</li>\n";
}
echo "</ol>\n";

1 Comment

I haven't tested this yet, but I understand the explanation. I'll give it a try but this looks good to me, thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.