TheTom
TheTom

Reputation: 1044

Transform array-structure in php

If I have an array which comes from a database like this:

$array = [  
    'dataset_1' => [
        'some' => '...',
        'array' => '...',
    ],  
    'dataset_2' => [
        'some' => '...',
        'thing' => '...',
        'else' => '...', 
    ] 
];

... how can I transform this array to another structure like:

$array = [ 
    'whatever' => [
        'some' =>'...',
        'array' => '...',
        'some' =>'...',
        'thing' => '...',
        'else' => '...',
    ] 
];

I thought about OptionResolver, but I have no idea so if anyone can give me a hint or an example?

Upvotes: 0

Views: 179

Answers (5)

Gbenankpon Arthur
Gbenankpon Arthur

Reputation: 167

To avoid overwriting duplicate keys, use this. So the duplicate keys in the array will successively take an integer.

// New array
foreach ($array as $key => $sub_array):
    foreach ($sub_array as $sub_key => $value):
        if (array_key_exists($sub_key,$new_array['whatever'])) {
            $i{$sub_key} = !isset($i{$sub_key}) ? 0 : $i{$sub_key};
            $sub_key = $sub_key . ++$i{$sub_key};
        }
        $new_array['whatever'][$sub_key] = $value;
    endforeach;
endforeach;

For example:

// Array
$array = [
    'dataset_1' => [
        'some' => '...',
        'array' => '...',
    ],
    'dataset_2' => [
        'some' => '...',
        'thing' => '...',
        'else' => '...',
    ],
    'dataset_3' => [
        'some' => '...',
        'thing' => '...',
        'else' => '...',
    ]
];

// New array
// the code...

print_r($new_array);

Output:

Array ( 
    [whatever] => Array ( 
        [some] => ... 
        [array] => ... 
        [some1] => ... 
        [thing] => ... 
        [else] => ... 
        [some2] => ... 
        [thing1] => ... 
        [else1] => ... 
        [some3] => ... 
        [thing2] => ... 
        [else2] => ... 
    ) 
)

Upvotes: 0

TheTom
TheTom

Reputation: 1044

Actually, I'm doing it by building a target array as template like:

Source array:
$array = [  
        'dataset_1' => [
            'keyFromSourceArray' => 'someValue',
            'array' => '...',
        ];

Destination array:

$array = [  
        'dataset_somename' => [
            'dataset_somename' => [
                'some' => 'keyFromSourceArray',
                'array' => '...',
        ],
];

Then, I cylce through the source array, grab the keys, and search and replace it by value in the destination array like:

public function array2api($needle, $array=false, array $path = []) {
foreach ($array as $key => $value) {
  $currentPath = array_merge($path, [$key]);
  if (is_array($value) && $result = $this->array2api($needle, $value, $currentPath)) {
    return $result;
  } else if ($value === $needle) {
    return $currentPath;
  }
}
return false;
}

This is working, but it is - I guess a bit laborious. As I can't fetch the source data from a db, I have to transform it anyway. But I guess theres a much easier solution for it which I didn't get yet.

Upvotes: 0

Arleigh Hix
Arleigh Hix

Reputation: 10877

One simple way to do this while ensuring no duplicate keys, is to concatenate the parent and child keys with a recursive loop:

$array = [  
    'dataset_1' => [
        'some' => '...',
        'array' => '...',
    ],  
    'dataset_2' => [
        'some' => '...',
        'thing' => '...',
        'else' => '...', 
    ] 
];
$flat_array = [];

foreach($array as $dataset => $data){
    foreach($data as $index => $value){
        $flat_array[$dataset . '_' . $index] = $value;
    }
}

var_export($flat_array);

Outputs:

array (
  'dataset_1_some' => '...',
  'dataset_1_array' => '...',
  'dataset_2_some' => '...',
  'dataset_2_thing' => '...',
  'dataset_2_else' => '...',
)

If your data gets more complex you can apply this same logic inside a recursive function that can handle many nested layers:

$array = [  
    'dataset_1' => [
        'some' => '...',
        'array' => '...',
    ],  
    'dataset_2' => [
        'some' => '...',
        'thing' => '...',
        'else' => [
            'cheese' => [
                'ball'  => true,
                'wheel' => false
                ],
            ], 
    ] 
];

function array_flatten ($array)
{
    $result = [];
    foreach($array as $i => $value)
    {
        if(!is_array($value)){
            $result[$i] = $value;
        }else{
            // pass array $value back to this same function
            $sub_result = array_flatten($value);
            foreach($sub_result as $subI => $subV)
            {
                // concatenate this index with each sub-index 
                // to get result index for each sub-value
                $result[$i . '_' . $subI] = $subV;
            }                
        }
    }
    return $result;
}

var_export(array_flatten($array));

Outputs:

array (
  'dataset_1_some' => '...',
  'dataset_1_array' => '...',
  'dataset_2_some' => '...',
  'dataset_2_thing' => '...',
  'dataset_2_else_cheese_ball' => true,
  'dataset_2_else_cheese_wheel' => false,
)

Upvotes: 0

Alex Barker
Alex Barker

Reputation: 4400

You are going to loose the duplicate key 'some' in both examples below.

$a = [  
   'dataset_1'=>[
      'some' =>'...',
      'array' => '...', ],  
   'dataset_2'=>[
      'some' =>'...',
      'thing' => '...',
      'else' => '...', 
   ] 
];

// You can use array union operator
$b = $a['dataset_1'] + $a['dataset_2'];

// Or you can use array merge.
$b = array_merge($a['dataset_1'], $a['dataset_2']);

Upvotes: 0

Vasilis G.
Vasilis G.

Reputation: 7846

You can do it using array_merge along with ..., in case you have an uknown number of datasets, to get your result. Beware though, as you have duplicate keys in your arrays which means that you will lose all duplicate keys but one. Consider using unique keys:

$input = array(  
   'dataset_1'=>[
      'some' =>'...',
      'array' => '...', ],  
   'dataset_2'=>[
      'some' =>'...',
      'thing' => '...',
      'else' => '...', 
   ] 
);


$output['whatever'] = array_merge(...array_values($input));
print_r($output);

Output:

Array
(
    [whatever] => Array
        (
            [some] => ...
            [array] => ...
            [thing] => ...
            [else] => ...
        )

)

Upvotes: 2

Related Questions