How do I create a multidimensional tree array from a flat array? - php

'I have this flat array:
$folders = [
'test/something.txt',
'test/hello.txt',
'test/another-folder/myfile.txt',
'test/another-folder/kamil.txt',
'test/another-folder/john/hi.txt'
]
And I need it in the following format:
$folders = [
'test' => [
'something.txt',
'hello.txt',
'another-folder' => [
'myfile.txt',
'kamil.txt',
'john' => [
'hi.txt'
]
]
]
];
How do I do this? Thanks.

Recursion is your friend :-)
function createArray($folders, $output){
if(count($folders) > 2){
$key = array_shift($folders);
$output[$key] = createArray(
$folders, isset($output[$key]) ? $output[$key] : []
);
}
else{
if(!isset($output[$folders[0]])){
$output[$folders[0]] = [];
}
$output[$folders[0]][] = $folders[1];
}
return $output;
}
Keep drilling down until you get to the file name, then add them all together in an array.
You need to call this function for each element in your array, like this:
$newFolders = [];
foreach($folders as $folder){
$newFolders = createArray(explode('/', $folder), $newFolders);
}
DEMO: https://eval.in/139240

<?php
$folders = [
'test/something.txt',
'test/hello.txt',
'test/another-folder/myfile.txt',
'test/another-folder/kamil.txt',
'test/another-folder/john/hi.txt'
];
$new_folders = array();
foreach ($folders as $folder) {
$reference =& $new_folders;
$parts = explode('/', $folder);
$file = array_pop($parts);
foreach ($parts as $part) {
if(!isset($reference[$part])) {
$reference[$part] = [];
}
$reference =& $reference[$part];
}
$reference[] = $file;
}
var_dump($new_folders);

Related

Convert multidimensional array to file path

How do i convert multidimensional array to file path.
I have this array :
$data = [
"users" => [
"joe" => [
"photos" => ["a.jpg","b.jpg"],
"files" => ["a.doc","b.doc"]
],
"annie" => [
"photos" => ["a.jpg","b.jpg"],
"files" => ["a.doc","b.doc"]
],
]
];
that i must convert to path example :
"users/joe/photos/a.jpg";
"users/joe/photos/b.jpg";
"users/joe/files/a.doc";
"users/joe/files/b.doc";
"users/annie/photos/a.jpg";
"users/annie/photos/b.jpg";
"users/annie/files/a.doc";
"users/annie/files/b.doc";
But i can't have the best result with this functions :
$path = "";
function iterate($data, $path)
{
echo "<br>";
foreach ($data as $key => $item){
if (is_array($item)){
$path .= $key.DIRECTORY_SEPARATOR;
iterate($item, $path);
}else{
echo $path.$item."<br>";
}
}
}
output :
users/joe/photos/a.jpg
users/joe/photos/b.jpg
users/joe/photos/files/a.doc
users/joe/photos/files/b.doc
users/joe/annie/photos/a.jpg
users/joe/annie/photos/b.jpg
users/joe/annie/photos/files/a.doc
users/joe/annie/photos/files/b.doc
Please help.
Thanks
You could make use of RecursiveIteratorIterator + RecursiveArrayIterator:
function computeFilePaths(array $fileTree): array
{
$filePaths = [];
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($fileTree));
foreach ($iterator as $fileName) {
for ($folders = [], $pos = 0, $depth = $iterator->getDepth(); $pos < $depth; $pos++) {
$folders[] = $iterator->getSubIterator($pos)->key();
}
$filePaths[] = implode('/', $folders) . '/' . $fileName;
}
return $filePaths;
}
print_r(computeFilePaths($yourArrayGoesHere));
I highly suggest this question's selected answer to understand how these iterators work.

Natural sort to multidimensional array in php

I have a api that returns requested images paths to front end. But in Linux server its needs natural sorting. I want to natural sort values in the yol key.
$klein->respond('GET', '/getPaths/[:name]', function($request,$response) {
$path00 = "../manga/" . $request->name;
function getAll($path00)
{
$dirs = [];
foreach (new DirectoryIterator($path00) as $item) {
if (!$item->isDir() || $item->isDot()) {
continue;
}
$gedo = [];
$path01 = $path00 . "/" . $item;
$path02 = substr($path01, 3);
$yol = new DirectoryIterator($path01);
foreach ($yol as $esya) {
if (!$esya->isDot() && $esya->getFilename() !== ".DS_Store") {
$gedo[] = $path02 . "/" . $esya->getFilename();
}
}
$dirs[] = array('klasor' => $item->getFilename(), 'yol' => $gedo);
}
return $dirs; // Output its in the image.
};
$data = getAll($path00);
$response->json($data);
});
Output:
Take a look at PHP sort functions. natsort should work for your case.
Simply change the following line to this:
natsort($gedo);
$dirs[] = array('klasor' => $item->getFilename(), 'yol' => $gedo);
Also a simple code example:
$input = [
'abc' => [
'item1',
'item4',
'item2'
]
];
$output = natsort($input['abc']); // $output will be true
// but $input is now sorted and looking like:
// 'abc' => [
// 'item1',
// 'item2',
// 'item4'
// ]

Creating a dynamic hierarchical array in PHP

I have this general data structure:
$levels = array('country', 'state', 'city', 'location');
I have data that looks like this:
$locations = array(
1 => array('country'=>'USA', 'state'=>'New York', 'city'=>'NYC', 'location'=>'Central Park', 'count'=>123),
2 => array('country'=>'Germany', ... )
);
I want to create hierarchical arrays such as
$hierarchy = array(
'USA' => array(
'New York' => array(
'NYC' => array(
'Central Park' => 123,
),
),
),
'Germany' => array(...),
);
Generally I would just create it like this:
$final = array();
foreach ($locations as $L) {
$final[$L['country']][$L['state']][$L['city']][$L['location']] = $L['count'];
}
However, it turns out that the initial array $levels is dynamic and can change in values and length So I cannot hard-code the levels into that last line, and I do not know how many elements there are. So the $levels array might look like this:
$levels = array('country', 'state');
Or
$levels = array('country', 'state', 'location');
The values will always exist in the data to be processed, but there might be more elements in the processed data than in the levels array. I want the final array to only contain the values that are in the $levels array, no matter what additional values are in the original data.
How can I use the array $levels as a guidance to dynamically create the $final array?
I thought I could just build the string $final[$L['country']][$L['state']][$L['city']][$L['location']] with implode() and then run eval() on it, but is there are a better way?
Here's my implementation. You can try it out here:
$locations = array(
1 => array('country'=>'USA', 'state'=>'New York', 'city'=>'NYC', 'location'=>'Central Park', 'count'=>123),
2 => array('country'=>'Germany', 'state'=>'Blah', 'city'=>'NY', 'location'=>'Testing', 'count'=>54),
);
$hierarchy = array();
$levels = array_reverse(
array('country', 'state', 'city', 'location')
);
$lastLevel = 'count';
foreach ( $locations as $L )
{
$array = $L[$lastLevel];
foreach ( $levels as $level )
{
$array = array($L[$level] => $array);
}
$hierarchy = array_merge_recursive($hierarchy, $array);
}
print_r($hierarchy);
Cool question. A simple approach:
$output = []; //will hold what you want
foreach($locations as $loc){
$str_to_eval='$output';
for($i=0;$i<count($levels);$i++) $str_to_eval .= "[\$loc[\$levels[$i]]]";
$str_to_eval .= "=\$loc['count'];";
eval($str_to_eval); //will build the array for this location
}
Live demo
If your dataset always in fixed structure, you might just loop it
$data[] = [country=>usa, state=>ny, city=>...]
to
foreach ($data as $row) {
$result[][$row[country]][$row[state]][$row[city]] = ...
}
In case your data is dynamic and the levels of nested array is also dynamic, then the following is an idea:
/* convert from [a, b, c, d, ...] to [a][b][...] = ... */
function nested_array($rows, $level = 1) {
$data = array();
$keys = array_slice(array_keys($rows[0]), 0, $level);
foreach ($rows as $r) {
$ref = &$data[$r[$keys[0]]];
foreach ($keys as $j => $k) {
if ($j) {
$ref = &$ref[$r[$k]];
}
unset($r[$k]);
}
$ref = count($r) > 1 ? $r : reset($r);
}
return $data;
}
try this:
<?php
$locations = [
['country'=>'USA', 'state'=>'New York', 'city'=>'NYC', 'location'=>'Central Park', 'street'=>'7th Ave', 'count'=>123],
['country'=>'USA', 'state'=>'Maryland', 'city'=>'Baltimore', 'location'=>'Harbor', 'count'=>24],
['country'=>'USA', 'state'=>'Michigan', 'city'=>'Lansing', 'location'=>'Midtown', 'building'=>'H2B', 'count'=>7],
['country'=>'France', 'state'=>'Sud', 'city'=>'Marseille', 'location'=>'Centre Ville', 'count'=>12],
];
$nk = array();
foreach($locations as $l) {
$jsonstr = json_encode($l);
preg_match_all('/"[a-z]+?":/',$jsonstr,$e);
$narr = array();
foreach($e[0] as $k => $v) {
if($k == 0 ) {
$narr[] = '';
} else {
$narr[] = ":{";
}
}
$narr[count($e[0]) -1] = ":" ;
$narr[] = "";
$e[0][] = ",";
$jsonstr = str_replace($e[0],$narr,$jsonstr).str_repeat("}",count($narr)-3);
$nk [] = $ko =json_decode($jsonstr,TRUE);
}
print_r($nk);
Database have three field:
here Name conatin contry state and city name
id,name,parentid
Pass the contry result to array to below function:
$data['contry']=$this->db->get('contry')->result_array();
$return['result']=$this->ordered_menu( $data['contry'],0);
echo "<pre>";
print_r ($return['result']);
echo "</pre>";
Create Function as below:
function ordered_menu($array,$parent_id = 0)
{
$temp_array = array();
foreach($array as $element)
{
if($element['parent_id']==$parent_id)
{
$element['subs'] = $this->ordered_menu($array,$element['id']);
$temp_array[] = $element;
}
}
return $temp_array;
}

Need help php to json array

I am having a string below
$string = ot>4>om>6>we>34>ff>45
I would like the JSON output be like
[{"name":"website","data":["ot","om","we","ff"]}]
and
[{"name":"websitedata","data":["4","6","34","45"]}]
what I've tried
$query = mysql_query("SELECT month, wordpress, codeigniter, highcharts FROM project_requests");
$category = array();
$category['name'] = 'website';
$series1 = array();
$series1['name'] = 'websitedata';
while($r = mysql_fetch_array($query)) {
$category['data'][] = $r['month'];
}
$result = array();
array_push($result,$category);
array_push($result,$series1);
print json_encode($result, JSON_NUMERIC_CHECK);
but the above code is applicable only if the data are present in rows from a mysql table, what i want is achieve the same result with the data from the above string. that is
$string = ot>4>om>6>we>34>ff>45
NEW UPDATE:
I would like to modify the same string
$string = ot>4>om>6>we>34>ff>45
into
json output:
[
{
"type" : "pie",
"name" : "website",
"data" : [
[
"ot",
4
],
[
"om",
6
],
[
"we",
34
]
]
}
]
I have updated the answer please check the json part, I would like the php code.
regards
You can explode() on the >s, and then loop through the elements:
$string = "ot>4>om>6>we>34>ff>45";
$array1 = [
'name'=>'website',
'data'=>[]
]
$array2 = [
'name'=>'websitedata',
'data'=>[]
]
foreach(explode('>', $string) as $index => $value){
if($index & 1) //index is odd
$array2['data'][] = $value;
else //index is even
$array1['data'][] = $value;
}
echo json_encode($array1); //prints {"name":"website","data":["ot","om","we","ff"]}
echo json_encode($array2); //prints {"name":"websitedata","data":["4","6","34","45"]}
A solution using preg_match_all():
$string = "ot>4>om>6>we>34>ff>45";
preg_match_all('/(\w+)>(\d+)/', $string, $matches);
$array1 = [
'name'=>'website',
'data'=> $matches[1]
];
$array2 = [
'name'=>'websitedata',
'data'=> $matches[2]
];
echo json_encode($array1); //prints {"name":"website","data":["ot","om","we","ff"]}
echo json_encode($array2); //prints {"name":"websitedata","data":["4","6","34","45"]}
Update:
To get the second type of array you wanted, use this:
//since json_encode() wraps property names in double quotes (which prevents the chart script from working), you'll have to build the json object manually
$string = "ot>4>om>6>we>34>ff>45";
preg_match_all('/(\w+)>(\d+)/', $string, $matches);
$data = [];
foreach($matches[1] as $index => $value){
if(isset($matches[2][$index]))
$data[] = '["' . $value . '",' . $matches[2][$index] . ']';
}
$type = 'pie';
$name = 'website';
echo $jsonString = '[{type:"' . $type . '",name:"' . $name . '",data:[' . implode(',', $data) . ']}]'; // prints [{type:"pie",name:"website",data:[["ot",4],["om",6],["we",34],["ff",45]]}]
Update #2:
This code uses explode(), and although it's probably not the most efficient way of doing it, it works.
//since json_encode() wraps property names in double quotes (which prevents the chart script from working), you'll have to build the json object manually
$string = "ot>4>om>6>we>34>ff>45";
$keys = [];
$values = [];
foreach(explode('>', $string) as $key => $value){
if(!($key & 1)) //returns true if the key is even, false if odd
$keys[] = $value;
else
$values[] = $value;
}
$data = [];
foreach($keys as $index => $value){
if(isset($values[$index]))
$data[] = '["' . $value . '",' . $values[$index] . ']';
}
$type = 'pie';
$name = 'website';
echo $jsonString = '[{type:"' . $type . '",name:"' . $name . '",data:[' . implode(',', $data) . ']}]'; // prints [{type:"pie",name:"website",data:[["ot",4],["om",6],["we",34],["ff",45]]}]
This should work, though there are probably better ways to do it.
$string = "ot>4>om>6>we>34>ff>45";
$website = ["name" => "website", "data" => []];
$websiteData = ["name" => "websitedata", "data" => []];
foreach(explode(">", $string) as $i => $s) {
if($i % 2 === 0) {
$website["data"][] = $s;
} else {
$websiteData["data"][] = $s;
}
}
echo json_encode($website);
echo json_encode($websiteData);
A regex alternative:
preg_match_all("/([a-z]+)>(\d+)/", $string, $matches);
$website = ["name" => "website", "data" => $matches[1]];
$websiteData = ["name" => "websitedata", "data" => $matches[2]];
Try this code:
$string = 'ot>4>om>6>we>34>ff>45';
$string_split = explode('>', $string);
$data = array("name" => "website");
$data2 = $data;
foreach ($string_split as $key => $value)
{
if (((int)$key % 2) === 0)
{
$data["data"][] = $value;
}
else
{
$data2["data"][] = $value;
}
}
$json1 = json_encode($data, JSON_NUMERIC_CHECK);
$json2 = json_encode($data2, JSON_NUMERIC_CHECK);
echo $json1;
echo $json2;
Output:
{"name":"website","data":["ot","om","we","ff"]}
{"name":"website","data":[4,6,34,45]}
Regards.
Try this snippet:
$strings = explode('>', 'ot>4>om>6>we>34>ff>45');
// print_r($string);
$x = 0;
$string['name'] = 'website';
$numbers['name'] = 'websitedata';
foreach ($strings as $s)
{
if ($x == 0) {
$string['data'][] = $s;
$x = 1;
} else {
$numbers['data'][] = $s;
$x = 0;
}
}
print_r(json_encode($string));
echo "<br/>";
print_r(json_encode($numbers));
As usual - it is long winded but shows all the steps to get to the required output.
<?php //https://stackoverflow.com/questions/27822896/need-help-php-to-json-array
// only concerned about ease of understnding not code size or efficiency.
// will speed it up later...
$inString = "ot>4>om>6>we>34>ff>45";
$outLitRequired = '[{"name":"website","data":["ot","om","we","ff"]}]';
$outValueRequired = '[{"name":"websitedata","data":["4","6","34","45"]}]';
// first: get a key / value array...
$itemList = explode('>', $inString);
/* debug */ var_dump(__FILE__.__LINE__, $itemList);
// outputs ------------------------------------
$outLit = array();
$outValue = array();
// ok we need to process them in pairs - i like iterators...
reset($itemList); // redundant but is explicit
// build both output 'data' lists
while (current($itemList)) {
$outLit[] = current($itemList);
next($itemList); // advance the iterator.
$outValue[] = current($itemList);
next($itemList);
}
/* debug */ var_dump(__FILE__.__LINE__, $itemList, $outLit, $outValue);
// make the arrays look like the output we want...
// we need to enclose them as arrays to get the exact formatting required
// i do that in the 'json_encode' statements.
$outLit = array('name' => 'website', 'data' => $outLit);
$outValue = array('name' => 'websitedata', 'data' => $outValue);
// convert to JSON.
$outLitJson = json_encode(array($outLit));
$outValueJson = json_encode(array($outValue));
// show required and calculated values...
/* debug */ var_dump(__FILE__.__LINE__, 'OutLit', $outLitRequired, $outLitJson);
/* debug */ var_dump(__FILE__.__LINE__, 'OutValue', $outValueRequired, $outValueJson);

How to dynamically create nested array in php

I want create a nested array from a config file dynamically.
My config file structure is like this:
parameter1 value1;
parameter2 value2;
parameter3 value3;
block1{
parameter1-1 value1-1;
parameter1-2 value1-2;
block1-1{
parameter1-1-1 value1-1-1;
parameter1-1-2 value1-1-2;
block1-1-1{
parameter1-1-1-1 value1-1-1-1;
parameter1-1-1-2 value1-1-1-2;
}
block1-1-2{
parameter1-1-2-1 value1-1-2-1;
parameter1-1-2-2 value1-1-2-2;
}
}
block1-2{
parameter1-2-1 value1-2-1;
parameter1-2-2 value1-2-2;
block1-2-1{
parameter1-2-1-1 value1-2-1-1;
parameter1-2-1-2 value1-2-1-2;
}
block1-2-2{
parameter1-2-2-1 value1-2-2-1;
parameter1-2-2-2 value1-2-2-2;
}
}
}
block2{
parameter2-1 value2-1;
parameter2-2 value2-2;
block2-1{
parameter2-1-1 value2-1-1;
parameter2-1-2 value2-1-2;
block2-1-1{
parameter2-1-1-1 value2-1-1-1;
parameter2-1-1-2 value2-1-1-2;
}
block2-1-2{
parameter2-1-2-1 value2-1-2-1;
parameter2-1-2-2 value2-1-2-2;
}
}
block2-2{
parameter2-2-1 value2-2-1;
parameter2-2-2 value2-2-2;
block2-2-1{
parameter2-2-1-1 value2-2-1-1;
parameter2-2-1-2 value2-2-1-2;
}
block2-2-2{
parameter2-2-2-1 value2-2-2-1;
parameter2-2-2-2 value2-2-2-2;
}
}
}
and i want this array dynamically in php:
$blocks = array(
$parameter => $value,
$parameter => $value,
$block => array(
$parameter => $value,
$parameter => $value,
$block => array(
$parameter => $value,
$parameter => $value,
$block => array(
$parameter => $value,
$parameter => $value
...
)
)
)
);
How to create dynamically nested array in PHP
Thanks.
UPDATE:
I read file line by line to an array and i want create above structure for edit it and write it again to config file.
I means from "dynamic" is creating array inside "for" or other similar things.
Try this... (change "conf.txt" to "your conf file name")
<?php
$file = fopen("conf.txt","r");
$array = array();
$a = createArray($file, $array);
fclose($file);
print("<pre>".print_r($a,true)."</pre>");
function createArray($file, $array){
while(! feof($file)){
$line = fgets($file);
$line = trim($line);
if ($line == ""){
continue;
}
if (strpos($line,'{') !== false){
$line = trim(str_replace('{','',$line));
$array[$line] = array();
$array[$line] = createArray($file, $array[$line]);
} else if (strpos($line,'}') !== false) {
return $array;
} else {
$line = str_replace(';','',$line);
$key = strtok($line, ' ');
$value = strtok(' ');
$array[$key] = $value;
}
}
return $array;
}
?>
Creating array dynamically:
in all PHP versions:
$foo = array();
in PHP 5.4+ (aka "short syntax"):
$foo = [];
Creating nested array dynamically:
$foo = [];
$foo['bar'] = [];
$foo['bar']['zoo'] = [];
or
$foo = [];
$bar = ['zoo' => []];
$foo['bar'] = $bar;
And finally call
print_r($foo);
to see what you got created. Both cases are equal so you will see:
Array
(
[bar] => Array
(
[zoo] => Array
(
)
)
}
Please see docs on array: http://php.net/manua/en/language.types.array.php

Categories