2

I have a flat resultset, that looks like this in JSON:

[{
    "LineItemNo": "1",
    "SolNo": "SPE8E7-15-T-1379",
    "St": "O",
    "PartNo": "F13DBX\/SPX35\/4P",
    "UnitPrice": "1.890"
}, {
    "LineItemNo": "1",
    "SolNo": "SPE8E7-15-T-1379",
    "St": "O",
    "PartNo": "CF13DD\/E\/835",
    "UnitPrice": "1.920"
}, {
    "LineItemNo": "1",
    "SolNo": "SPE8E7-15-T-1379",
    "St": "O",
    "PartNo": "QT13\/35-4",
    "UnitPrice": "1.770"
}, {
    "LineItemNo": "2",
    "SolNo": "SPE8E7-15-T-4309",
    "St": "O",
    "PartNo": "F13DBX\/SPX35\/4P",
    "UnitPrice": "1.890"
}, {
    "LineItemNo": "2",
    "SolNo": "SPE8E7-15-T-4309",
    "St": "O",
    "PartNo": "CF13DD\/E\/835",
    "UnitPrice": "1.920"
}, {
    "LineItemNo": "2",
    "SolNo": "SPE8E7-15-T-4309",
    "St": "O",
    "PartNo": "QT13\/35-4",
    "UnitPrice": "1.770"
}]

I want to change it into this:

{
    "data": [{
        "LineItemNo": "1",
        "SolNo": "SPE8E7-15-T-1379",
        "St": "O",
        "Parts": [{
            "PartNo": "F13DBX\/SPX35\/4P",
            "UnitPrice": "1.890"
        }, {
            "PartNo": "CF13DD\/E\/835",
            "UnitPrice": "1.920"
        }, {
            "PartNo": "QT13\/35-4",
            "UnitPrice": "1.770"
        }]
    }, {
        "LineItemNo": "2",
        "SolNo": "SPE8E7-15-T-4309",
        "St": "O",
        "Parts": [{
            "PartNo": "F13DBX\/SPX35\/4P",
            "UnitPrice": "1.890"
        }, {
            "PartNo": "CF13DD\/E\/835",
            "UnitPrice": "1.920"
        }, {
            "PartNo": "QT13\/35-4",
            "UnitPrice": "1.770"
        }]
    }]
}

I've tried numerous things, but I haven't been able to find a way to iterate through the source array, create a Parts array during the process, and then plug values into that array during subsequent iterations. What I'd like to do is iterate the source array, check the $row['LineItemNo'] value, and if it has changed since the last iteration, create a new top-level array object. If it hasn't, then create a new element the Parts array.

My basic code looks like this (I realize mysql is deprecated in favor of mysqli or PDO, but I'm stuck with it for the time being):

$result = mysql_query($query) or die(mysql_error());
$rs = array();
$rsParts = array();
while($row = mysql_fetch_array($result))
{
    if (!isset($ln) || $row['LineItemNo'] != $ln)
    {
        $ln = $row['LineItemNo'];
        $rs[data][] = array('LineItemNo' => $row['LineItemNo'], 'SolNo' => $row['SolNo'], 'St' => $row['St']);
        $rs[data][parts] = array();
    }
    array_push($rs[data][parts], array('PartNo' => $row['PartNo'], 'UnitPrice' => $row['UnitPrice']));
}

This is a good start, but it only gives me the parts in the first element, like this:

{
    "data": {
        "0": {
            "LineItemNo": "1",
            "SolNo": "SPE8E7-15-T-1379",
            "St": "O"
        },
        "parts": [{
            "PartNo": "F13DBX\/SPX35\/4P",
            "UnitPrice": "1.890"
        }, {
            "PartNo": "CF13DD\/E\/835",
            "UnitPrice": "1.920"
        }, {
            "PartNo": "QT13\/35-4",
            "UnitPrice": "1.770"
        }],
        "1": {
            "LineItemNo": "2",
            "SolNo": "SPE8E7-15-T-4309",
            "St": "O"
        }
    }
}

I'm thinking that you can't re-initialize the array this way. I've tried unsetting it when the LineItemNo changes, but that turns all the Parts elements into top-level elements. I've tried only initializing the array at the beginning using is_array, but that puts all of the parts into the first top-level element (there are six parts in the first one and none in the second).

So, what's the right way to do what I'm trying to do?

EDIT: the solution of the problem was to first send the resultset ($result) through this code:

$array = array();
while($r = mysql_fetch_assoc($result))
{
    $array[] = $r;
}

And then use SML's solution from there.

0

2 Answers 2

2

Assuming any given LineItemNo would always be paired with the same SolNo and St, you can pass LineItemNo of each row to a function to check if the value exists in the sub-arrays of the result array $rs.

If LineItemNo doesn't already exist in $rs, then a new first level sub array of $rs is created and a 2nd level sub array containing parts info will also be added as sub_array of 1st level array element parts.

If LineItemNo does exist, then just add the parts info as sub_array of 1st level array element parts.

Since the top level array ['data'] you wanted in the output, doesn't do anything at this stage.
I strip that from the process and instead $rs is added to $output['data'] in the final stage to form the output you need.

$rs=array();
$counter=0;
while($r = mysql_fetch_assoc($results)) {
    $array[]=$r;
}

foreach ($array as $row) { 
  $part_info = array('part_no' => $row['PartNo'], 'unit_price' => $row['UnitPrice']);
  $temp=searchSub ($rs, $row['LineItemNo']);

    if ($temp===false){
       $rs[$counter] = array('LineItemNo' => $row['LineItemNo'], 'SolNo' => $row['SolNo'], 'St' => $row['St']);
       $rs[$counter]['parts'][] = $part_info;
       $counter++;
    }
    else {
        $rs[$temp]['parts'][]= $part_info;
    }
}
//function for subarray search
function searchSub($arr, $keyword){
    foreach($arr as $key=>$value)
    {
        if (in_array($keyword, $value, true)!=false){
        return $key;
        }
    }
    return false;
}
$output['data']=$rs;
print_r($output);

Test Result

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

15 Comments

Why the counter? $key will do the exact same thing. It's redundant. Also why the search function?
@MikeBarwick the OP wants to move parts_info that shares the same lineitemno, solno and st to as sub arrays to the array parts, not just move part_info to a sub array. I hope I didn't misinterpret the questoin
@MikeBarwick $key would result in 5 sub-arrays, at the level after 'data', the output the OP wants should only have 2 sub-arrays at the level after 'data'
No. There's a good chance I have lol I give up. Hopefully this solves OPs. :)
No, SML, you interpreted the question correctly. Thanks for taking a crack at this. I find when I run this code, all the values are '1' for the first element (including all the values for parts), 'S', for the second one, 'O' for the third, and 'F' for the fourth. Not sure where that's coming from, but I had something similar when messing with foreach. Also, there are four parts for the first, and two for the next three. There should be two top-level elements (removing data until the end is a good idea), with three parts each.
|
2

array_push is the way I'd typically do it. You're code is a bit confusing to read (not very user friendly), but I think you're close - very close...

EDIT: Check out the below. Should work. Change your while to a foreach and run it like so:

$rs = [];

foreach(mysql_fetch_array($result) as $key => $row) 
{
    $rs['data'][$key] = array('LineItemNo' => $row['LineItemNo'], 'SolNo' => $row['SolNo'], 'St' => $row['St']);

    $part_info = array('part_no' => $row['PartNo'], 'unit_price' => $row['UnitPrice']);
    $rs['data'][$key]['parts'] = $part_info;
}

print_r($rs);

12 Comments

Thanks Mike. That's closer, but not all the way. I only get the parts for the first top-level element. I'll edit my post to incorporate this.
Ok, not sure how to do that I guess. I've edited my answer as well to show what I've tried. Oh, I had to use array() instead of [], for some reason I was getting a syntax error. Might that have anything to do with the problem?
Check my edits for some ideas. Note, $rs[data][parts] should be $rs['data']['parts']
Curiously, I thought the keys had to be in quotes too, but I tried them without and they worked.
Prob explains why [] weren't working as na array - as it's the same thing. What PHP version you on?
|

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.