2

Apologies if this has been asked but I can't find a solution that meets my needs.

I have an array in a PHP 7 application as follows:

$data = [
    0 => [
        'regulations_label' => 'Europe',
        'groups_label' => 'G1',
        'filters_label' => 'FF1'
    ],
    1 => [
        'regulations_label' => 'Europe',
        'groups_label' => 'G1',
        'filters_label' => 'FF900'
    ],
    2 => [
        'regulations_label' => 'Europe',
        'groups_label' => 'G1',
        'filters_label' => 'FF324234'
    ],
    3 => [
        'regulations_label' => 'Europe',
        'groups_label' => 'G2',
        'filters_label' => 'FF23942'
    ],
    4 => [
        'regulations_label' => 'America',
        'groups_label' => 'G29',
        'filters_label' => 'FF3242'
    ],
    5 => [
        'regulations_label' => 'America',
        'groups_label' => 'G29',
        'filters_label' => 'FF78978'
    ],
    6 => [
        'regulations_label' => 'America',
        'groups_label' => 'G29',
        'filters_label' => 'FF48395043'
    ],
    7 => [
        'regulations_label' => 'Asia',
        'groups_label' => 'G2000',
        'filters_label' => 'FF7'
    ],
    // ...
];

The output I want to achieve is like this:

Europe
    - G1
        -- FF1
        -- FF900
    - G2
        -- FF23942

America
    - G29
        -- FF3242
        -- FF48395043

Asia
    - G2000
        -- FF7

Essentially all it's doing is outputting the array in a structured format such that it shows the regulations_label followed by any corresponding groups_label and then any filters_label.

It's simple enough to loop through the entire array, e.g.

foreach ($data as $d) {
    echo $d['regulations_label'] . "\n";
    echo ' - ' . $d['groups_label'] . "\n";
    echo ' -- ' . $d['filters_label'] . "\n";
}

However this introduces "duplicate" headings for regulations_label and groups_label because it's printing every single key. But I don't see how I can check if this has changed during the foreach statement because $d is always the current element.

I was attempting to do a check based on the previous array key:

foreach ($data as $key => $d) {
   if ($data[$key-1]['regulations_label'] !== $d['regulations_label']) {
       echo $d['regulations_label'] . "\n";
       echo "-" . $d['groups_label'] . "\n";
   }
}

The trouble is that this then just prints 1 groups_label so I'd end up with - for example:

Europe
- G1
America
...

It wouldn't get as far as "G2".

I can't help but think I'm going about this in a bizarre way. Can anyone advise a better solution?

Background info: The data I receive in $data isn't something I can modify because that format is required for the use case which is a feature in an application like this: jQuery load more data on scroll

Andy
  • 5,142
  • 11
  • 58
  • 131

3 Answers3

7

you can use foreach and group by using regulations_label and groups_label

$group = [];
foreach($data as $v){
  $group[$v['regulations_label']][$v['groups_label']][] = $v['filters_label'];
}

DEMO

Rakesh Jakhar
  • 6,380
  • 2
  • 11
  • 20
2

In the simplest case you just need to add some if statements as you'd started to do, but you also have to make sure they only stop the relevant bit from printing - your version was suppressing the whole output, instead of just the top-level label:

foreach ($data as $key => $d) {
   if ($key > 0) {
       if ($data[$key-1]['regulations_label'] !== $d['regulations_label']) {
           echo $d['regulations_label'] . "\n";   

       }
       if ($data[$key-1]['groups_label'] !== $d['groups_label']) {
           echo "-" . $d['groups_label'] . "\n";
       }
   }
   else
   {
       //special case to deal with first row where $key-1 doesn't exist
       echo $d['regulations_label'] . "\n";   
       echo "-" . $d['groups_label'] . "\n";
   }
   echo ' -- ' . $d['filters_label'] . "\n";
}

Demo: https://3v4l.org/ihYVj

ADyson
  • 57,178
  • 14
  • 51
  • 63
  • This is a good solution as it causes fewer issues than the accepted answer with the memory overhead from the `$group` array. It's giving a `Notice: Undefined offset: -1 ` error though. – Andy Jun 21 '19 at 07:57
  • @Andy sorry about that... see updated demo and code sample above. It's just an issue with the first row, because obviously when $key is 0, there's no array index at $key-1! – ADyson Jun 21 '19 at 08:17
0

All you need to do is remember what you last processed and then adda couple of IF's

$data = [
    0 => ['regulations_label' => 'Europe','groups_label' => 'G1','filters_label' => 'FF1'],
    1 => ['regulations_label' => 'Europe','groups_label' => 'G1','filters_label' => 'FF900'],
    2 => ['regulations_label' => 'Europe','groups_label' => 'G1','filters_label' => 'FF324234'],
    3 => ['regulations_label' => 'Europe','groups_label' => 'G2','filters_label' => 'FF23942'],
    4 => ['regulations_label' => 'America','groups_label' => 'G29','filters_label' => 'FF3242'],
    5 => ['regulations_label' => 'America','groups_label' => 'G29','filters_label' => 'FF78978'],
    6 => ['regulations_label' => 'America','groups_label' => 'G29','filters_label' => 'FF48395043'],
    7 => ['regulations_label' => 'Asia','groups_label' => 'G2000','filters_label' => 'FF7']
];

$last_reg = NULL;
$last_grp = NULL;

foreach ($data as $reg) {

    if ( $last_reg != $reg['regulations_label']) {
        echo $reg['regulations_label'] . "\n";
        $last_reg = $reg['regulations_label'];
        $last_grp = NULL;
        $last_filter = NULL;
    }
    if ( $last_grp != $reg['groups_label']) {
        echo "\t - " . $reg['groups_label'] . "\n";
        $last_grp = $reg['groups_label'];
    }
    echo "\t\t - " . $reg['filters_label'] . "\n";
}

RESULT:

Europe
     - G1
         - FF1
         - FF900
         - FF324234
     - G2
         - FF23942
America
     - G29
         - FF3242
         - FF78978
         - FF48395043
Asia
     - G2000
         - FF7
RiggsFolly
  • 93,638
  • 21
  • 103
  • 149