1

OK, here's the challenge I'm facing and it is quite a complicated one :

  • I'm having a multi-dimensional array (it can be just an array or it can go several levels deep)
  • I have a set of "allowed" keys (containing "parent.child" keys as well)
  • In the final array, we only need numeric keys and allowed keys. All the rest has to be dropped from the final table.

Example initial array :

Array
(
    [0] => Array
        (
            [Title] => La science des rêves
            [Year] => 2006
            [Director] => Array
                (
                    [Name] => Michel Gondry
                    [BirthYear] => 1963
                    [BirthPlace] => Versailles, Yvelines, France
                )

        )

    [1] => Array
        (
            [Title] => Arizona Dream
            [Year] => 1992
            [Director] => Array
                (
                    [Name] => Emir Kusturica
                    [BirthYear] => 1954
                    [BirthPlace] => Sarajevo, Bosnia and Herzegovina, Yugoslavia
                )

        )

)

Example allowed keys :

Array
(
    [0] => Title
    [1] => Director.Name
    [2] => Director.BirthYear
)

I want to filter it so that the final array contains just the above keys (the numeric keys will be kept no-matter-what) :

Array
(
    [0] => Array
        (
            [Title] => La science des rêves
            [Director.Name] => Michel Gondry
            [Director.BirthYear] => 1963
        )

    [1] => Array
        (
            [Title] => Arizona Dream
            [Director.Name] => Emir Kusturica
            [Director.BirthYear] => 1954
        )
)

Any ideas on how to do this? I've been struggling for hours, with all sorts of recursive functions but I'm always seemingly missing something... :S

3 Answers 3

1

First of all it's obvious you need a function that can flatten arbitrarily nested arrays. When you do this there's always the chance of key collisions if the input is engineered to produce them, but in your case that's not an issue so you would be OK with something like

function flatten($array, $separator = '.') {
    foreach ($array as $key => $value) {
        if (!is_array($value)) {
            continue;
        }

        unset ($array[$key]);

        foreach (flatten($value, $separator) as $subkey => $subval) {
            $array[$key.$separator.$subkey] = $subval;
        }

    }

    return $array;
}

You can now flatten each one of your "initial" rows with:

$flattened = array_map('flatten', $initial);

That leaves the problem of filtering out keys based on your whitelist, which you could do with

$whitelist = array_flip(['Title', 'Director.Name', /* etc */]);

$filter = function($array) use (&$whitelist) {
    return array_intersect_key($array, $whitelist);
};

$filtered = array_map($filter, $flattened);
Sign up to request clarification or add additional context in comments.

4 Comments

Impressive and ultra-fast. What more could I say? Thanks. Thanks. Thanks. :-)
@Dr.Kameleon: Glad to help. Look into the functions I used, PHP has a lot of useful building blocks like that. Building a solution is not that hard once you know they 're there.
I know about PHP's powerful function library and - even though I kinda hate it "visually" - it's one of the main reasons I love it. However, my main issue here was - believe-or-not - this... unset command, which has triggered enough weird issues for me in the past to make me afraid of it...
PHP-powered or not though, your solution is as elegant as it could get. And I rest my case. :-)
1
<?php 

$array  =  array(Array(

                    "Title" => 'La science des rêves',
                    "Year" => '2006',
                    'Director' => Array
                    (
                        'Name' => 'Michel Gondry',
                        'BirthYear' => '1963',
                        'BirthPlace' => 'Versailles, Yvelines, France',
                    )

                ),

                Array
                    (
                        'Title' => 'Arizona Dream',
                        'Year' => '1992',
                        'Director' => Array
                            (
                                'Name' => 'Emir Kusturica',
                                'BirthYear' => '1954',
                                'BirthPlace' => 'Sarajevo, Bosnia and Herzegovina, Yugoslavia'
                            )
                    )

            );


/*
            [Title] => La science des rêves
            [Director.Name] => Michel Gondry
            [Director.BirthYear] => 1963*/


echo '<pre>';
print_r($array);
echo '</pre>';

foreach($array as $final)
{

    $final_array[]    =   array(
                                'title'=>$final['Title'], 
                                'name'=>$final['Director']['Name'],
                                'birthyear'=> $final['Director']['BirthYear']
                            );

}

echo '<pre>';
print_r($final_array);
echo '</pre>';

Comments

1

try this

$arr=Array
(
    0 => Array
        (
            "Title" => "La science des rêves",
            "Year" => "2006",
            "Director" => Array
                (
                    "Name" => "Michel Gondry",
                    "BirthYear" => "1963",
                    "BirthPlace" => "Versailles, Yvelines, France"
                )

        ),

    1 => Array
        (
            "Title" => "Arizona Dream",
            "Year" => "1992",
            "Director" => Array
                (
                    "Name" => "Emir Kusturica",
                    "BirthYear" => "1954",
                    "BirthPlace" => "Sarajevo, Bosnia and Herzegovina, Yugoslavia"
                )

        )

);

$ck=Array
(
    0 => "Title",
    1 => "Director.Name",
    2 => "Director.BirthYear"
);


$newarray=array(array());
$s=sizeof($arr);
$ss=0;

    while($ss<$s)
    {
        foreach($ck as $ck2)
{
$k = explode(".",$ck2);
if(sizeof($k) > 1)
    $newarray[$ss][$ck2]=$arr[$ss][$k[0]][$k[1]];
        else
    $newarray[$ss][$ck2]=$arr[$ss][$k[0]];


    }$ss++;
}

print_r($newarray);

Demo

Comments

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.