-1

I need a help. I'm looking for a solution for this problem! I have a file which contains the following pattern:

Brazil|SaoPaulo|Diadema|RuadaFe Brazil|SaoPaulo|Diadema|RuadoLimoeiro Brazil|SaoPaulo|SaoCaetano|RuadasLaranjeiras Brazil|Parana|Curitiba|ComendadorAraujo USA|NewJersey|JerseyCity|WhashingtonBoulervard USA|NewJersey|JerseyCity|RiverCourt

Which should bring after some array key implementation, something like this (after apply json_encode call on php):

{
    "name": "Brazil",
    "children": [
    {
        "name": "SaoPaulo",
        "children": [
            {
                "name": "Diadema",
                "children": [
                    {"name": "RuadaFe"},
                    {"name": "RuadoLimoeiro"}
                ]
            },
            {
                "name": "SaoCaetano",
                "children": [
                    {"name": "RuadasLaranjeiras"}
                ]
            },
        ]
        "name": "Parana",
        "children": [
            {
                "name": "Curitiba",
                "children": [
                    {"name": "ComendadorAraujo"}
                ]
            }
       ]
    },
    "name":"USA",
    "children":[
      {
         "name": "NewJersey",
          "children": [
            {
                "name": "JerseyCity",
                "children": [
                    {"name": "WhashingonBoulevard"},
                    {"name": "RiverCourt"}
                ]
            }
          ]
       }
     ]
  }
 ]

And keep going and going (and even more deeper too). Please, help me team... thanks in advance.

Here what I get until now:

Array ( [Brazil] => Array ( [SaoPaulo] => Array ( [Diadema] => Array ( [RuadoLimoeiro] => )

                [SaoCaetano] => Array
                    (
                        [RuadasLaranjeiras] => 
                    )

            )

        [Parana] => Array
            (
                [Curitiba] => Array
                    (
                        [ComendadorAraujo] => 
                    )

            )

    )

[USA] => Array
    (
        [NewJersey] => Array
            (
                [JerseyCity] => Array
                    (
                        [WhashingtonBoulervard] => 
                        [RiverCourt] => 
                    )

            )

    )

)

And here is the json encoded:

{
"Brazil":{
"SaoPaulo":
   {"Diadema":
       {"RuadoLimoeiro":null},
       "SaoCaetano":{"RuadasLaranjeiras":null}
       },
"Parana":
   {"Curitiba":
       {"ComendadorAraujo":null}
   }
},
"USA":{
"NewJersey":{
"JerseyCity":{
     "WhashingtonBoulervard":null,
     "RiverCourt":null}
      }
    }
}

As you can see, the "names" and "child" is missing because is not an array key structure, also something is wrong, because I'm missing some values on SaoPaulo.

Here is the function:

foreach($strings as $string) {
    $parts = array_filter(explode('|', $string));
    $ref = &$result;
    foreach($parts as $p) {
       // echo $p;
        if(!isset($ref[$p])) {
            $ref[$p] = array();
           // $ref[$p] = array("name"=>$p);
        }

        $ref = &$ref[$p];

    }
    $ref = null;
}

-------------------------------- AFTER SOME ANSWERS --------------------------

{
    "name": "Brazil(country)",
    "children": [
    {
        "name": "SaoPaulo(state)", // only one state
        "children": [
            {
                "name": "Diadema(city)", // only one city
                "children": [
                    {"name": "RuadaFe(street)"}, // two streets under the same city...
                    {"name": "RuadoLimoeiro(street)"}
                ]
            },
            {
                "name": "SaoCaetano(city)",
                "children": [
                    {"name": "RuadasLaranjeiras(street)"}
                ]
            },
        ]
        "name": "Parana(state)",
        "children": [
            {
                "name": "Curitiba(city)",
                "children": [
                    {"name": "ComendadorAraujo(street)"}
                ]
            }
       ]
    },...

I put on parentesis the structure (country, state, city, street) just to clarify what i want. Got it?

3
  • 1
    So you've told us what you want. Now let us know what your programming question is. Commented Apr 30, 2013 at 16:15
  • So your problem are the keys? so that you have this nice for json? Commented Apr 30, 2013 at 16:27
  • The original post was edited, with the results that I have now, and the function that I'm using. Commented Apr 30, 2013 at 16:28

2 Answers 2

0

It is not outright trivial, but what I did is actually the same as you (the same way as in your edited question), but I also keep track of those arrays to rename the keys. And that's what I do afterwards then:

$separator = [' ', '|'];

$buffer = file_get_contents($file);
$entries = explode($separator[0], $buffer);
$result = [];
$named[] = &$result;
########
foreach ($entries as $entry) {
    $each     = explode($separator[1], $entry);
    $pointer  = & $result;
    while ($current = array_shift($each)) {
        if (!isset($pointer[$current])) {
            unset($children);
            $children = [];
            $named[] = &$children;
            ########
            $pointer[$current] = ['name' => $current, 'children' => &$children];
        }
        $pointer = & $pointer[$current]['children'];
    }
}

foreach($named as $offset => $namedArray) {
    $keys = array_keys($namedArray);
    foreach($keys as $key) {
        $named[$offset][] = &$namedArray[$key];
        unset($named[$offset][$key]);
    }
}

print_r($result);

See it in action.

You probably might want to modify this by checking in the later foreach if children are empty (leaf-nodes) and then removing the children entry as well.

Here the modified foreach at the end and json output:

foreach($named as $offset => $namedArray) {
    $keys = array_keys($namedArray);
    foreach($keys as $key) {
        if (!$namedArray[$key]['children']) {
            unset($namedArray[$key]['children']);
        }
        $named[$offset][] = &$namedArray[$key];
        unset($named[$offset][$key]);
    }
}

echo json_encode($result, JSON_PRETTY_PRINT);

Output:

[
    {
        "name": "Brazil",
        "children": [
            {
                "name": "SaoPaulo",
                "children": [
                    {
                        "name": "Diadema",
                        "children": [
                            {
                                "name": "RuadaFe"
                            },
                            {
                                "name": "RuadoLimoeiro"
                            }
                        ]
                    },
                    {
                        "name": "SaoCaetano",
                        "children": [
                            {
                                "name": "RuadasLaranjeiras"
                            }
                        ]
                    }
                ]
            },
            {
                "name": "Parana",
                "children": [
                    {
                        "name": "Curitiba",
                        "children": [
                            {
                                "name": "ComendadorAraujo"
                            }
                        ]
                    }
                ]
            }
        ]
    },
    {
        "name": "USA",
        "children": [
            {
                "name": "NewJersey",
                "children": [
                    {
                        "name": "JerseyCity",
                        "children": [
                            {
                                "name": "WhashingtonBoulervard"
                            },
                            {
                                "name": "RiverCourt"
                            }
                        ]
                    }
                ]
            }
        ]
    }
]

The full code-example at a glance:

<?php
/**
 * PHP - Nested array keys based on string lines
 * @link http://stackoverflow.com/a/16305236/2261774
 */
$file = 'data://text/plain;base64,' . base64_encode('Brazil|SaoPaulo|Diadema|RuadaFe Brazil|SaoPaulo|Diadema|RuadoLimoeiro Brazil|SaoPaulo|SaoCaetano|RuadasLaranjeiras Brazil|Parana|Curitiba|ComendadorAraujo USA|NewJersey|JerseyCity|WhashingtonBoulervard USA|NewJersey|JerseyCity|RiverCourt');

$separator = [' ', '|'];

$buffer = file_get_contents($file);
$entries = explode($separator[0], $buffer);
$result = [];
$named[] = &$result;
foreach ($entries as $entry) {
    $each     = explode($separator[1], $entry);
    $pointer  = & $result;
    while ($current = array_shift($each)) {
        if (!isset($pointer[$current])) {
            unset($children);
            $children = [];
            $named[] = &$children;
            $pointer[$current] = ['name' => $current, 'children' => &$children];
        }
        $pointer = & $pointer[$current]['children'];
    }
}
unset($pointer);

foreach($named as $offset => $namedArray) {
    $keys = array_keys($namedArray);
    foreach($keys as $key) {
        if (!$namedArray[$key]['children']) {
            unset($namedArray[$key]['children']);
        }
        $named[$offset][] = &$namedArray[$key];
        unset($named[$offset][$key]);
    }
}
unset($named);

echo json_encode($result, JSON_PRETTY_PRINT);

your question JSON:

{
    "name": "Brazil",
    "children": [
    {
        "name": "SaoPaulo",
        "children": [
            {
                "name": "Diadema",
                "children": [
                    {"name": "RuadaFe"},
                    {"name": "RuadoLimoeiro"}
                ]
            },

My Answer JSON:

[
    {
        "name": "Brazil",
        "children": [
            {
                "name": "SaoPaulo",
                "children": [
                    {
                        "name": "Diadema",
                        "children": [
                            {
                                "name": "RuadaFe"
                            },
                            {
                                "name": "RuadoLimoeiro"
                            }
                        ]
                    },

The only difference I can spot is that the root-nodes are wrapped inside an array in my answer, but it should be trivial to fetch them out there if that really is your issue ;)

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

5 Comments

Thanks.. but it is not what I expected.. The problem is in the structure.. I'll put on my question what I want structured..
@RobertoRitter: Better compare closely. This is exactly as you have placed the json in your question. - See the last edit.
Sorry, didn't see your answer properly.. yes.. it is this structure, however something is getting error on line 8 ($separator = [' ', '|'];)..... Parse error: syntax error, unexpected '[' in
@RobertoRitter : Your version of PHP does not support this new syntax for array. Just make it the old way : $separator = array(' ','|');
Is it possible to add another keys inside of each children? code[ { "name": "Brazil", "children": [ { "name": "SaoPaulo", "children": [ { "name": "Diadema", "children": [ { "name": "RuadaFe", "alert": 0, "zipcode":"98123" },
0

Does it solves your problem? Use $inputString to put your real string.

    <?php

// ------------------------------------------------------ your input goes here ------------------------------------------------------
$inputString = 'Brazil|SaoPaulo|Diadema|RuadaFe Brazil|SaoPaulo|Diadema|RuadoLimoeiro Brazil|SaoPaulo|SaoCaetano|RuadasLaranjeiras Brazil|Parana|Curitiba|ComendadorAraujo USA|NewJersey|JerseyCity|WhashingtonBoulervard USA|NewJersey|JerseyCity|RiverCourt';

class item {
    public $name = null;

    public function getChildrenByName($strName) {

        $ret = null;
        # this variable should be defined in interface, but i skipped it so it wont be printed in json when obj does not have childrens
        if( !isset( $this->children ) ) {
            $this->children = array(  );
        }

        foreach ( $this->children as $child ) {
            if( $child->name === $strName ) {
                $ret = $child;
                break;
            }
        }


        if ( !$ret ) {
            $this->children[] = self::spawnByName( $strName );
        }

        return $this->children[ count($this->children) - 1];
    }

    static public function spawnByName($strName) {
        $ret = new item();
        $ret->name = $strName;
        return $ret;
    }
}

class listManager {

    protected $list = array();

    public function getList() {
        return $this->list;
    }

    public function addPath( $desiredPath ) {

        # path needs to be as array
        if ( is_string( $desiredPath ) ) {
            $desiredPath = explode('|', $desiredPath);
        }

        # create root element if it does not already exists
        if ( !isset( $this->list[$desiredPath[0]] ) ) {
            $this->list[$desiredPath[0]] = item::spawnByName($desiredPath[0]);
        }

        $curElement = $this->list[$desiredPath[0]];

        for( $i=1; $i<count($desiredPath); $i++ ) {
            $curElement = $curElement->getChildrenByName( $desiredPath[$i] );
        }

    }

    protected function spawnElement( $strName ) {
        $ret = new item();
        $ret->name = $strName;
        return $ret;
    }
}

$output = array();
$expl = explode(' ', $inputString);
$list = new listManager();

foreach ( $expl as $key => $path ) {
    $list->addPath( $path );

}

$output = '';

foreach ( $list->getList() as $singleVariable ) {
    $output .= json_encode($singleVariable, JSON_PRETTY_PRINT) . ",\n";
}

echo '<pre>'.$output.'</pre>';

?>

Above code produces following json out of your sample code:

{
    "name": "Brazil",
    "children": [{
            "name": "SaoPaulo",
            "children": [{
                    "name": "Diadema",
                    "children": [{
                            "name": "RuadaFe"
                        }
                    ]
                }
            ]
        }, {
            "name": "SaoPaulo",
            "children": [{
                    "name": "Diadema",
                    "children": [{
                            "name": "RuadoLimoeiro"
                        }
                    ]
                }
            ]
        }, {
            "name": "SaoPaulo",
            "children": [{
                    "name": "SaoCaetano",
                    "children": [{
                            "name": "RuadasLaranjeiras"
                        }
                    ]
                }
            ]
        }, {
            "name": "Parana",
            "children": [{
                    "name": "Curitiba",
                    "children": [{
                            "name": "ComendadorAraujo"
                        }
                    ]
                }
            ]
        }
    ]
} {
    "name": "USA",
    "children": [{
            "name": "NewJersey",
            "children": [{
                    "name": "JerseyCity",
                    "children": [{
                            "name": "WhashingtonBoulervard"
                        }
                    ]
                }
            ]
        }, {
            "name": "NewJersey",
            "children": [{
                    "name": "JerseyCity",
                    "children": [{
                            "name": "RiverCourt"
                        }
                    ]
                }
            ]
        }
    ]
}

edit: changed, does it fit now?

3 Comments

No, The structure is not as is in your output example. The streets must be inside the same child structure on the cities which has to be in same structure of country... example: "name":"USA", "children":[ { "name": "NewJersey", "children": [ { "name": "JerseyCity", "children": [ {"name": "WhashingonBoulevard"}, {"name": "RiverCourt"} ]....
{ "name": "Brazil(country)", "children": [ { "name": "SaoPaulo(state)", "children": [ { "name": "Diadema(city)", "children": [ {"name": "RuadaFe(street)"}, {"name": "RuadoLimoeiro(street)"} ] }, { "name": "SaoCaetano(city)", "children": [ {"name": "RuadasLaranjeiras(street)"} ] }, ] "name": "Parana(state)", "children": [ { "name": "Curitiba(city)", "children": [ {"name": "ComendadorAraujo(street)"} ...I put on parentesis the structure (country, state, city, street) just to clarify what i want.
See diff mergely.com/uPt243aB (btw you can not place two "name" and two "children" properties in one object, so you will need to adjust your sample) Beyond that i see that my output matches it

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.