0

I want to group an associative array by fields. The array itself is originally from a mysql database query.

Below is an example of how I do it by hard coding it:

<?php
$fields = array("ID,subID");
$fieldCounts = count($fields);
$data = array(); //there is sql querieed data



$parsedData = array();

foreach ($data as $val)
{
    if ($fieldCounts == 1)
    {
        $f0 = $fields[0];
        $fv0 = $val[$f0];
        $parsedData[$fv0][] = $val;
    }
    else if ($fieldCounts == 2)
    {
        $f0 = $fields[0];
        $fv0 = $val[$f0];
        $f1 = $fields[10];
        $fv1 = $val[$f1];
        $parsedData[$fv0][$f1][] = $val;
    }
    else
    {
        exit("Third field not implemented");
    }
}
?>

But how can I do it dynamically with an arbitrary number of fields?

ekad
  • 14,436
  • 26
  • 44
  • 46
Infira
  • 167
  • 1
  • 11
  • Related: [Checking if array exists within multidimensional array - no looping - unknown depth](http://stackoverflow.com/q/9010035/367456) – hakre Oct 26 '12 at 11:06
  • @Infira Please improve this question by offering some sample resultset data. When we better understand your input data and your desired output, volunteers can better answer and researchers can better relate to your question (and potentially upvote it). – mickmackusa Aug 24 '18 at 08:02

2 Answers2

2

Am not sure how this code has worked for you but some things are that wrong and might not allow the code to function properly

  • Fields has only as one valued with ,

    $fields = array("ID,subID"); 
                       ^----------- between string 
    

    Instead of

    $fields = array("ID","subID");
    
  • Notice: Undefined offset:

    $f1 = $fields[10];
                   ^----- your array is not up to 10
    

Since you did not put your generate data and desired output. I would assume your final output and generate some temporary data

$fields = array("ID","subID"); //You can Increase or decrease this Fields
$fieldCounts = count($fields);
$data = array(); // there is sql querieed data

for($i = 0; $i < 3; $i ++) {
    $data[] = array("ID" => mt_rand(1, 1000),"subID" => "sub" . mt_rand(100, 900));
}

Ruining your code with the 2 corrections above

foreach ( $data as $val ) {
    if ($fieldCounts == 1) {
        $f0 = $fields[0];
        $fv0 = $val[$f0];
        $parsedData[$fv0][] = $val;
    } else if ($fieldCounts == 2) {
        $f0 = $fields[0];
        $fv0 = $val[$f0];
        $f1 = $fields[1];
        $fv1 = $val[$f1];
        $parsedData[$fv0][$f1][] = $val;
    } else {
        exit("Third field not implemented");
    }
}

Output

Array
(
    [159] => Array
        (
            [subID] => Array  <----------- SubID is fixed in your can cause confict
                (
                    [0] => Array
                        (
                            [ID] => 159
                            [subID] => sub589
                        )

                )

        )

    [334] => Array
        (
            [subID] => Array
                (
                    [0] => Array
                        (
                            [ID] => 334
                            [subID] => sub703
                        )

                )

        )

)

A better Alternative to yours

$parsedData = array();
foreach ( $data as $val ) {
    $temp = &$parsedData;
    foreach ( array_slice($val, 0, $fieldCounts) as $key ) {
        $temp = &$temp[$key];
    }
    $temp[] = $val;
}
print_r($parsedData);

Output

Array
(
    [159] => Array
        (
            [sub589] => Array <---------- Make Sub ID Dynamic 
                (
                    [0] => Array
                        (
                            [ID] => 159
                            [subID] => sub589
                        )

                )

        )

    [334] => Array
        (
            [sub703] => Array
                (
                    [0] => Array
                        (
                            [ID] => 334
                            [subID] => sub703
                        )

                )

        )

)

Recommended Version For easy array path

$parsedData = array();
foreach ( $data as $val ) {
    $temp = &$parsedData;
    foreach ( array_slice($val, 0, $fieldCounts) as $key ) {
        $temp = &$temp[$key];
    }
    $temp = $val; 
}
print_r($parsedData);

Output

Array
(
    [159] => Array
        (
            [sub589] => Array <---- Easy to asses as $parsedData['159']['sub589']
                (
                    [ID] => 159
                    [subID] => sub589
                )

        )

    [334] => Array
        (
            [sub703] => Array
                (
                    [ID] => 334
                    [subID] => sub703
                )

        )

)
Baba
  • 94,024
  • 28
  • 166
  • 217
1

Instead of doing if/elseif/else inside your $data foreach-loop (which is always limited to the number you "write" in there with that structure and a lot of code-duplicateion) you need to turn that if/elseif/else into a loop of it's own.

But first of all transform the existing code, I start in the first if body, it contains already all code necessary:

$f0  = $fields[0];
$fv0 = $val[$f0];
$parsedData[$fv0][] = $val;

The $val should be assigned to the array $parsedData which is keyed by $fields name $value. Let's compress this here, the number 0 in names is superfluous as we don't want it any longer (but maybe the first):

$field = $fields[0];
$value = $values[$field];

$parsedData[$value][] = $values;

(I changed $val into $values to improve naming). This is now more easy to read and understand. Also we spot the magic number 0 here more easily.

Now to the magic. We want to add to an array here (push):

$parsedData[$value][] = $values;

To make this more easy, let's turn it this way:

$array   = &$parsedData[$value];
$array[] = $values;

This right now seems superfluous, but when this turns into a loop, it will become more clear:

$array   = &$parsedData;

...

$array   = &array[$value];

...

$array[] = $values;

Let's review the code in with the outer loop at this moment:

foreach ($data as $values)
{

    $array   = &$parsedData; 

    $field = $fields[0];
    $value = $values[$field];        
    $array = &$array[$value];

    $array[] = $values;
}

Obviously this code is yet not complete. The inner-loop is missing but it starts to get some kind of body. And actually the inner loop is pretty simple to achieve:

$array   = &$parsedData; 

foreach ($fields as $field)
{
    $value = $values[$field];
    $array = &$array[$value];
}

$array[] = $values;

And that's already it. The single field has been turned into an iteration over all fields. The aliasing/referencing of the sub-array per each step in the iteration allows to push the value to the appropriate array entry after the inner loop has finished.

The whole outer and inner loop:

foreach ($data as $values)
{
    $array   = &$parsedData; # set reference

    foreach ($fields as $field)
    {
        $value = $values[$field];
        $array = &$array[$value];
    }

    $array[] = $values;

    unset($array); # remove reference
}
hakre
  • 193,403
  • 52
  • 435
  • 836