Search code examples
phplaravel-8

Regroup array values using dynamic keys (PHP)


I have this array, but it has duplicate values.

 $syncData = array(
            (object)[
                "orgUnitId" => "1",
                "orgUnitName" => "josh",
                "sive" => "OK",
                "siim" => null,
                "hosp"=>null,
                "date" => "2023-01-19 00:00:00"
            ],
            (object)[
                "orgUnitId" => "1",
                "orgUnitName" => "josh",
                "sive" => null,
                "siim" => "ERROR",
                "hosp" => null,
                "date" => "2023-01-19 00:00:00"
            ],
            (object)[
                "orgUnitId" => "1",
                "orgUnitName" => "josh",
                "sive" => null,
                "siim" => null,
                "hosp" => "OK",
                "date" => "2023-01-19 00:00:00"
            ],
            (object)[
                "orgUnitId" => "2",
                "orgUnitName" => "Bill",
                "sive" => "OK",
                "siim" => null,
                "hosp" => null,
                "date" => "2023-01-19 00:00:00"
            ],
            (object)[
                "orgUnitId" => "2",
                "orgUnitName" => "Bill",
                "sive" => null,
                "siim" => "ERROR",
                "hosp" => null,
                "date" => "2023-01-19 00:00:00"
            ],
            (object)[
                "orgUnitId" => "2",
                "orgUnitName" => "Bill",
                "sive" => null,
                "siim" => null,
                "hosp" => "ERROR",
                "date" => "2023-01-19 00:00:00"
            ],
          
        );

The orgUnitId, orgUnitName are repeated and different objects. I want the values of sive, siim and hosp to be placed in a single object as shown below.

 $syncData = array(           
            (object)[
                
                "orgUnitId" => "1",
                "orgUnitName" => "josh",
                "sive" => OK,
                "siim" => "ERROR",
                "hosp" => "OK",
                "date" => "2023-01-19 00:00:00"
            ],           
            (object)[
               
                "orgUnitId" => "2",
                "orgUnitName" => "Bill",
                "sive" => "OK",
                "siim" => "ERROR",
                "hosp" => "ERROR",
                "date" => "2023-01-19 00:00:00"
            ],
          
        );

But the keys sive, siim and hosp are dynamic, ie they come from another array as shown below.

   $serversList = array(
          (object)[
            "name"=> "sive"
          ],
           (object)[
            "name"=>  "siim"
           ],
            (object)[
            "name" =>  "hosp"
            ]
        );

But to know the keys sive, siim and hosp you must use another array. Because they are dynamic, that is, they can change their quantity (sive, siim , hosp, deco, hub). Example: we can have:

  (object)[
                "orgUnitId" => "2",
                "orgUnitName" => "Bill",
                "sive" => null,
                "siim" => null,
                "hosp" => "ERROR",
                "deco" =>  null,
                 "hub" => null
                "date" => "2023-01-19 00:00:00"
            ],

I tried this but it doesent work

 for ($i = 0; $i < (count($syncData)-1); $i++) {
            foreach ($serversList as $serverkey => $serverValue) {
              if($syncData[$i]->{$serverValue->name}==null){
                    $val= $syncData[$i];
                    $val->{$serverValue->name}= $syncData[$i + 1]->{$serverValue->name};
                    array_push($data_copy,$val);
              }
            }
        }

I get this result:

 $syncData = array(
            (object)[
                "orgUnitId" => "1",
                "orgUnitName" => "josh",
                "sive" => "OK",
                "siim" => "ERROR",
                "hosp"=>null,
                "date" => "2023-01-19 00:00:00"
            ],
            (object)[
                "orgUnitId" => "1",
                "orgUnitName" => "josh",
                "sive" => null,
                "siim" => "ERROR",
                "hosp" => "ERROR",
                "date" => "2023-01-19 00:00:00"
            ],
            (object)[
                "orgUnitId" => "1",
                "orgUnitName" => "josh",
                "sive" => "OK",
                "siim" => null,
                "hosp" => "ERROR",
                "date" => "2023-01-19 00:00:00"
            ],
            (object)[
                "orgUnitId" => "2",
                "orgUnitName" => "Bill",
                "sive" => "OK",
                "siim" => null,
                "hosp" => null,
                "date" => "2023-01-19 00:00:00"
            ],
            (object)[
                "orgUnitId" => "2",
                "orgUnitName" => "Bill",
                "sive" => null,
                "siim" => "ERROR",
                "hosp" => null,
                "date" => "2023-01-19 00:00:00"
            ],
            (object)[
                "orgUnitId" => "2",
                "orgUnitName" => "Bill",
                "sive" => null,
                "siim" => null,
                "hosp" => "ERROR",
                "date" => "2023-01-19 00:00:00"
            ],
          
        );

Solution

  • Things like this are always quite easy to do, when you use a "helper" array, in that you insert the items under whatever the grouping "key" is.

    Here that grouping key is the combination of unit id and unit name - so I am sticking both into an array and encode that as JSON, so that both values combined result in one string value, that we can use as array key.

    Then we can go "look up" whether the item already exists in our helper array, and only needs additional properties added to it, or if we need to create it.

    And array_values resets those keys to a normal, zero-based numeric index again afterwards.

    $helper = [];
    foreach ($syncData as $item) {
        $key = json_encode([$item->orgUnitId, $item->orgUnitName]);
        foreach ($serversList as $serverValue) {
            if(!isset($helper[$key])) {
                $helper[$key] = (object) [
                    'orgUnitId' => $item->orgUnitId,
                    'orgUnitName' => $item->orgUnitName,
                    'date' => $item->date,
                ];
            }
            if ($item->{$serverValue->name} !== null) {
                $helper[$key]->{$serverValue->name} = $item->{$serverValue->name};
            }
        }
    }
    $helper = array_values($helper);
    
    print_r($helper);
    

    Result:

    Array
    (
        [0] => stdClass Object
            (
                [orgUnitId] => 1
                [orgUnitName] => josh
                [date] => 2023-01-19 00:00:00
                [sive] => OK
                [siim] => ERROR
                [hosp] => OK
            )
    
        [1] => stdClass Object
            (
                [orgUnitId] => 2
                [orgUnitName] => Bill
                [date] => 2023-01-19 00:00:00
                [sive] => OK
                [siim] => ERROR
                [hosp] => ERROR
            )
    
    )
    

    You'll note that the order of the properties is a bit different (date moved up, due to when it got added) - but I suppose that should probably not matter much? (If it does, you could work with an array instead of objects, then sort those arrays by key in the desired order afterwards, and only then cast them into stdClass objects again.)