satya
satya

Reputation: 3560

Could not sort json object by same key using PHP

I am trying to sort json object by same key and merge the value part using PHP but not getting the result as expected. My code is below:

$customArr=[{"attribute_code":"budget","value":"141"},{"attribute_code":"restaurants","value":"166"},{"attribute_code":"food_type","value":"172"},{"attribute_code":"budget","value":"142"},{"attribute_code":"restaurants","value":"168"},{"attribute_code":"food_type","value":"173"},{"attribute_code":"budget","value":"143"},{"attribute_code":"restaurants","value":"170"},{"attribute_code":"food_type","value":"173"},{"attribute_code":"budget","value":"162"},{"attribute_code":"restaurants","value":"171"},{"attribute_code":"food_type","value":"172"}]
function sortByName($a, $b){
    $a = $a['attribute_code'];
    $b = $b['attribute_code'];

    if ($a == $b) return 0;
    return ($a < $b) ? -1 : 1;
}
usort($customArr, 'sortByName');

Here I need if attribute_code is same then push the respective value into one array and also the duplicate value should not be there. The expected result is given below.

[{"attribute_code":"budget","value":[141,142,143,162]},{}.....]

But in my case the expected result not coming.

Upvotes: 1

Views: 69

Answers (4)

Dhananjay Yadav
Dhananjay Yadav

Reputation: 273

The similar solution as above, but a little different using a temp variable and in a single iteration:

<?php 
$str='[{"attribute_code":"budget","value":"141"},{"attribute_code":"restaurants","value":"166"},{"attribute_code":"food_type","value":"172"},{"attribute_code":"budget","value":"142"},{"attribute_code":"restaurants","value":"168"},{"attribute_code":"food_type","value":"173"},{"attribute_code":"budget","value":"143"},{"attribute_code":"restaurants","value":"170"},{"attribute_code":"food_type","value":"173"},{"attribute_code":"budget","value":"162"},{"attribute_code":"restaurants","value":"171"},{"attribute_code":"food_type","value":"172"}]';
$arr = json_decode($str,true);
$temp = $result= [];
foreach($arr as $key=>$customer){
    if(in_array($customer['attribute_code'], $temp)){
        $index=array_search($customer['attribute_code'],$temp);
        if(!in_array($customer['value'],$result[$index]['value'])){
            $result[$index]['value'][]=$customer['value'];
        }
    }else {
        $temp[]=$customer['attribute_code'];
        $result[]=[
            'attribute_code'=>$customer['attribute_code'],
            'value'=>[$customer['value']]
        ];
    }
}
unset($temp);
print_r($result);
echo json_encode($result);
?>

Result :

Array
(
[0] => Array
    (
        [attribute_code] => budget
        [value] => Array
            (
                [0] => 141
                [1] => 142
                [2] => 143
                [3] => 162
            )

    )

[1] => Array
    (
        [attribute_code] => restaurants
        [value] => Array
            (
                [0] => 166
                [1] => 168
                [2] => 170
                [3] => 171
            )

    )

[2] => Array
    (
        [attribute_code] => food_type
        [value] => Array
            (
                [0] => 172
                [1] => 173
            )

    )

)

JSON ENCODED RESPONSE

  [{"attribute_code":"budget","value":["141","142","143","162"]},{"attribute_code":"restaurants","value":["166","168","170","171"]},{"attribute_code":"food_type","value":["172","173"]}]

Upvotes: 0

Nigel Ren
Nigel Ren

Reputation: 57131

At the moment you are just sorting the entries according to the attribute_code and doing nothing about merging the data items.

This code creates a new output array (keyed it by the attribute_code), if the code is already there it adds the value into the list of existing values, if not it adds a new item in, creating the value as an array (with the first item in). Lastly it uses ksort() to sort the items.

If you don't need these keys, then array_values() will give you a plain array (as in the output)...

$json='[{"attribute_code":"budget","value":"141"},{"attribute_code":"restaurants","value":"166"},{"attribute_code":"food_type","value":"172"},{"attribute_code":"budget","value":"142"},{"attribute_code":"restaurants","value":"168"},{"attribute_code":"food_type","value":"173"},{"attribute_code":"budget","value":"143"},{"attribute_code":"restaurants","value":"170"},{"attribute_code":"food_type","value":"173"},{"attribute_code":"budget","value":"162"},{"attribute_code":"restaurants","value":"171"},{"attribute_code":"food_type","value":"172"}]';

$customArr = json_decode($json, true);
$output = [];
foreach ( $customArr as $attribute )    {
    if ( isset ( $output[$attribute['attribute_code']]))    {
        $output[$attribute['attribute_code']]['value'][] = $attribute['value'];
    }
    else    {
        $output[$attribute['attribute_code']] = ["attribute_code"=>$attribute['attribute_code'],
            "value"=> [$attribute['value']]];
    }
}
// Make sure values are unique
foreach ( $output as $code => $value ){
    $output[$code]['value'] = array_unique($output[$code]['value']);
}
ksort($output);
print_r(array_values($output));

gives...

Array
(
    [0] => Array
        (
            [attribute_code] => budget
            [value] => Array
                (
                    [0] => 141
                    [1] => 142
                    [2] => 143
                    [3] => 162
                )

        )

    [1] => Array
        (
            [attribute_code] => food_type
            [value] => Array
                (
                    [0] => 172
                    [1] => 173
                )

        )

    [2] => Array
        (
            [attribute_code] => restaurants
            [value] => Array
                (
                    [0] => 166
                    [1] => 168
                    [2] => 170
                    [3] => 171
                )

        )

)

Upvotes: 1

MH2K9
MH2K9

Reputation: 12039

Using array_reduce() you can try it. array_reduce() callback takes two arguments, who's first argument is the old/previous iteration value and second argument is the current iteration value/element.

So using this function we can holds our current iteration values to the previous iteration value (total values).

array_reduce() iteratively reduce the array to a single value using a callback function.

$customArr = json_decode('[{"attribute_code":"budget","value":"141"},{"attribute_code":"restaurants","value":"166"},{"attribute_code":"food_type","value":"172"},{"attribute_code":"budget","value":"142"},{"attribute_code":"restaurants","value":"168"},{"attribute_code":"food_type","value":"173"},{"attribute_code":"budget","value":"143"},{"attribute_code":"restaurants","value":"170"},{"attribute_code":"food_type","value":"173"},{"attribute_code":"budget","value":"162"},{"attribute_code":"restaurants","value":"171"},{"attribute_code":"food_type","value":"172"}]', true);

$data = array_reduce($customArr, function ($acc, $new) {
    if (isset($acc[$new['attribute_code']])) {
        $old_value = $acc[$new['attribute_code']]['value'];
        $acc[$new['attribute_code']]['value'] = array_unique(is_array($old_value) ? array_merge($old_value, [$new['value']]) : [$old_value, $new['value']]);
    } else {
        $acc[$new['attribute_code']] = $new;
    }
    return $acc;
}, []);

ksort($data);

echo '<pre>', json_encode(array_values($data));

Working demo.

Upvotes: 2

You have a JSON string, not an array.

$jsonString = '[{"attribute_code":"budget","value":"141"},{"attribute_code":"restaurants","value":"166"},{"attribute_code":"food_type","value":"172"},{"attribute_code":"budget","value":"142"},{"attribute_code":"restaurants","value":"168"},{"attribute_code":"food_type","value":"173"},{"attribute_code":"budget","value":"143"},{"attribute_code":"restaurants","value":"170"},{"attribute_code":"food_type","value":"173"},{"attribute_code":"budget","value":"162"},{"attribute_code":"restaurants","value":"171"},{"attribute_code":"food_type","value":"172"}]';
$customArr = json_decode($jsonString, true);

    function sortByName($a, $b)
    {
        $a = $a['attribute_code'];
        $b = $b['attribute_code'];

        if ($a == $b) return 0;
        return ($a < $b) ? -1 : 1;
    }

    usort($customArr, 'sortByName');

Upvotes: 0

Related Questions