Search code examples
phpjsonmultidimensional-arraygrouping

Merge rows of data while grouping rows by multiple identifying columns


I have my data look like:

[{"REG":"SK", "RES":"PAN1", "WELL":"P1-TG", "TIME":"2005-03-27"},
{"REG":"SK", "RES":"PAN1", "WELL":"P1-TG", "TIME":"2005-04-13"},
{"REG":"SK", "RES":"PAN1", "WELL":"P1-TG", "TIME":"2006-06-07"},
{"REG":"SK", "RES":"PAN2", "WELL":"P2-TG", "TIME":"2009-01-18"},
{"REG":"SK", "RES":"PAN3", "WELL":"P3-TG", "TIME":"2009-03-01"},
{"REG":"SK", "RES":"PAN3", "WELL":"P3-TG", "TIME":"2010-03-14"}]

and this is my code:

$query =[{my data}];
$list = [];

foreach($query as $index => $q){
     if($index != 0){
         $key = $index - 1;
         $filter = [];
         if($q->WELL == $query[$key]->WELL){ 
             array_push($list,array_merge_recursive(json_decode(json_encode($q),true),json_decode(json_encode($query[$key]),true)));
         }else{
             array_push($list,$q);
         }
     }else{
         array_push($list,$q);
     }
}

my result after run by my code:

[{"REG":"SK", "RES":"PAN1", "WELL":"P1-TG", "TIME":"2005-03-27"},
    {"REG":["SK","SK"], "RES":["PAN1","PAN1"], "WELL":["P1-TG","P1-TG"], "TIME":["2005-03-27","2005-04-13"]},
    {"REG":["SK","SK"], "RES":["PAN1","PAN1"], "WELL":["P1-TG","P1-TG"], "TIME":["2005-04-13","2006-06-07"]},
    {"REG":"SK", "RES":"PAN2", "WELL":"P2-TG", "TIME":"2009-01-18"},
    {"REG":"SK", "RES":"PAN3", "WELL":"P3-TG", "TIME":"2009-03-01"},
    {"REG":["SK","SK"], "RES":["PAN3","PAN3"], "WELL":["P3-TG","P3-TG"], "TIME":["2009-03-01","2010-03-14"]}]

and what I want is:

[{"REG":"SK", "RES":"PAN1", "WELL":"P1-TG", "TIME":["2005-03-27","2005-04-13","2006-06-07"]},
{"REG":"SK", "RES":"PAN2", "WELL":"P2-TG", "TIME":"2009-01-18"},
{"REG":"SK", "RES":"PAN3", "WELL":"P3-TG", "TIME":["2009-03-01","2010-03-14"]}]

Solution

  • Manipulating array data while in json format is a cumbersome and usually error-prone endeavor. The first thing to do is convert the json to an array so that you can employ php's simple and powerful array handling functions.

    You want to group the data based on the first three element values. To do this efficiently, you create temporary composite keys -- that is, temporary associative keys which contain the combined values as a string.

    This helps your code to determine whether you are dealing with the first occurrence or not. This is valuable information because you wish to store data differently based on this knowledge.

    Code: (Demo)

    $json = '[{"REG":"SK", "RES":"PAN1", "WELL":"P1-TG", "TIME":"2005-03-27"},
    {"REG":"SK", "RES":"PAN1", "WELL":"P1-TG", "TIME":"2005-04-13"},
    {"REG":"SK", "RES":"PAN1", "WELL":"P1-TG", "TIME":"2006-06-07"},
    {"REG":"SK", "RES":"PAN2", "WELL":"P2-TG", "TIME":"2009-01-18"},
    {"REG":"SK", "RES":"PAN3", "WELL":"P3-TG", "TIME":"2009-03-01"},
    {"REG":"SK", "RES":"PAN3", "WELL":"P3-TG", "TIME":"2010-03-14"}]';
    
    foreach (json_decode($json, true) as $row) {  // convert json to array and iterate rows
        $composite_key = implode('-', array_slice($row, 0, 3));  // group by the first 3 row values
        if (!isset($result[$composite_key])) {  // if 1st occurrence of first 3 row values
            $row['TIME'] = [$row['TIME']];      // adjust last value in row to be a subarray
            $result[$composite_key] = $row;     // store the full data
        } else {
            $result[$composite_key]['TIME'][] = $row['TIME'];  // push only the TIME value into the subarray
        }
    }
    echo json_encode(array_values($result), JSON_PRETTY_PRINT);  // re-index, convert to json and display
    

    Output: (you don't need to use PRETTY_PRINT, it's just easier to read my answer)

    [
        {
            "REG": "SK",
            "RES": "PAN1",
            "WELL": "P1-TG",
            "TIME": [
                "2005-03-27",
                "2005-04-13",
                "2006-06-07"
            ]
        },
        {
            "REG": "SK",
            "RES": "PAN2",
            "WELL": "P2-TG",
            "TIME": [
                "2009-01-18"
            ]
        },
        {
            "REG": "SK",
            "RES": "PAN3",
            "WELL": "P3-TG",
            "TIME": [
                "2009-03-01",
                "2010-03-14"
            ]
        }
    ]