recursion function on tree data to get path - php

I want to write function which receive me path to top element, but I can't figure out how it should work..
My example data:
$data = array(
3546456 => array(
5345345,
12312312,
56456546,
),
12312312 => array(
34534534,
5675675,
8678678,
),
567978 => array(
234,
756756,
8678678,
),
);
//I have function to return parent.
$parents = getParents(8678678); // eg. $object_id = 8678678 - return [12312312, 567978] , $object_id = 12312312 - return [3546456]
// and my recursion function I tried.
function getObjectPath($object_id) {
if ($object_id == null) {
return [];
}
$parents = getObjectParents($object_id);
foreach ($parents as $parent) {
return array($object_id => getObjectPath($parent->nid));
}
}
It doesn't work way I need, on the return in getObjectPath(8678678) I'd like to have return array like that:
array(
3546456 => array(
12312312 => array(
8678678
)
),
567978 => array(
8678678
)
);

I think you almost got it, need to have some other check before returning
$data = array(
3546456 => array(
5345345,
12312312,
56456546,
),
12312312 => array(
34534534,
5675675,
8678678,
),
567978 => array(
234,
756756,
8678678,
),
);
//I have function to return parent.
$parents = getObjectPath(8678678, $data); // eg. $object_id = 8678678 - return [12312312, 567978] , $object_id = 12312312 - return [3546456]
echo "<pre>";
print_r($parents);
// and my recursion function I tried.
function getParents($object_id, $data) {
$return = [];
foreach($data as $key => $value) {
if(in_array($object_id, $value)) {
$return[] = $key;
}
}
return $return;
}
// and my recursion function I tried.
function getObjectPath($object_id, $data) {
$return = [];
$parents = getParents($object_id, $data);
foreach($parents as $parent) {
$temp = getObjectPath($parent, $data);
if(!empty($temp)) {
$return[key($temp)][$parent] = $object_id;
} else {
$return[$parent] = $object_id;
}
}
return $return;
}

Related

php multidimensional array recursively into an object

I have a multidimensional array that i would like to create into an object so I can then output both as xml and json.
I am having difficulty getting my head around how to do this recursively. I have looked at many multidimensional posts I can find on here but am still stuck.
What am I doing wrong?
class Dataset
{
public $name;
public $attr = array();
public $children = array();
function __construct($name){
$this->name = $name;
}
function addAttr($attr){
$this->attr[] = $attr;
}
function addChildren($children){
$this->children[] = $children;
}
}
$jazzy = Array(
name => 'aaa',
attr => Array(
id => 123
),
children => Array(
Array(
name => 'name',
attr => Array(),
children => Array(
'www'
),
),
Array(
name => 'websites',
attr => Array(),
children => Array(
Array(
name => 'website',
attr => Array(
id => 456,
class => 'boom'
),
children => Array(
Array(
name => 'url',
attr => Array(),
children => Array(
'www.test.com'
)
)
)
),
Array(
name => 'website',
attr => Array(
id => 123,
class => "boom"
),
children => Array(
Array(
name => 'url',
attr => Array(),
children => Array(
'www.example.com'
)
)
)
)
)
)
)
);
I am looking to create this output
<aaa id="123">
<name>www</name>
<websites>
<website id='456' class="boom">
<url>www.test.com</url>
</website>
<website id='123 class="boom">
<url>www.example.com</url>
</website>
</websites>
</aaa>
My code
function arrayToDataset($array, $node){
foreach ($array as $key => $value) {
$name = $array['name'];
$attr = $array['attr'];
$children = $array['children'];
if($key == "name"){
$name = $value;
$node->addName($name);
}
elseif($key == "attr"){
$attr = $value;
$node->addAttr($attr);
}
elseif($key == "children")
{
$children = $value;
$newNode = new Dataset();
foreach($children as $k => $v)
{
$newNode = $node->addChildren($v);
}
return arrayToDataset($children, $newNode);
}
}
}
$node = new Dataset();
$thing = arrayToDataset($jazzy, $node);
print_r($thing);
This may be a way to parse the data into your DataSet object, which you could then use to output in some other format like xml or json. There may be easier ways to do that though...
class Dataset
{
public $name;
public $attr = array();
public $children = array();
public $url = array();
function __construct($name)
{
$this->name = $name;
}
function addAttr($attr, $value)
{
$this->attr[$attr] = $value;
}
function addChild(DataSet $child)
{
$this->children[] = $child;
}
function addUrl($url) {
$this->url[] = $url;
}
static function makeNode($array)
{
// $array needs to have the required elements
$node = new DataSet($array['name']);
if (isset($array['attr'])) {
foreach ($array['attr'] as $k => $v) {
if (is_scalar($v)) {
$node->addAttr($k, $v);
}
}
}
if (isset($array['children']) && is_array($array['children'])) {
foreach ($array['children'] as $c) {
if(is_scalar($c)) {
$node->addUrl($c);
} else {
$node->addChild(self::makeNode($c));
}
}
}
return $node;
}
}
print_r(Dataset::makeNode($jazzy));

return all keys of nested array

given a nested array of arbitrary depth like this:
$array = array(
1400=>
array(7300=>
array(
7301=> array(),
7302=> array(),
7305=> array(
7306=>array()
),
),
7314=>array()
),
);
how would one get the hierarchy of keys for any key.
for example:
getkeys(7305);
should return 1400,7300,7305 in that order
or
getkeys(7314);
should return 1400,7314
all array keys are unique values
Using RecursiveIteratorIterator
$array = array(
1400 => array(
7300 => array(
7301=> array(),
7302 => array(),
7305 => array(
7306=>array()
),
),
7314=>array()
),
);
function getKeys($key, $array) {
$found_path = [];
$ritit = new RecursiveIteratorIterator(new RecursiveArrayIterator($array), RecursiveIteratorIterator::SELF_FIRST);
foreach ($ritit as $leafValue) {
$path = array();
foreach (range(0, $ritit->getDepth()) as $depth) {
$path[] = $ritit->getSubIterator($depth)->key();
}
if (end($path) == $key) {
$found_path = $path;
break;
}
}
return $found_path;
}
print_r(getKeys(7305, $array));
// Array
// (
// [0] => 1400
// [1] => 7300
// [2] => 7305
// )
This is very interesting problem you have so I tried to make a function that will echo your keys. If this is not good enough pls let me know I can improve code. Thanks.
<?php
$a = array(
1400=>
array(7300=>
array(
7301=> array(),
7302=> array(),
7305=> array(
7306=>array()
),
),
7314=>array()
),
);
$mykey = 7306;
$level = 0;
$result = array();
$resultarray = test($a,$mykey,$level,$result);
function test($array,$mykey,$level,$result){
$level++;
foreach($array as $key => $element){
if($key == $mykey){
echo 'found';
print_r($result);
exit;
} else if(is_array($element)){
$result[$level] = $key;
$result1 = test($element,$mykey,$level,$result);
}
}
}
The idea is to check current array branch, and if the needle key isn't found, then iterate current items and check their array child nodes by recursive function calls. Before each step down we push a current key to stack, and pop the stack if the function does not found a needle key in whole branch. So if the key found, the function returns true by the chain, preserving successful keys in the stack.
function branchTraversing(& $branch, & $key_stack, $needle_key) {
$found = false;
if (!array_key_exists($needle_key, $branch)) {
reset($branch);
while (!$found && (list($key, $next_branch) = each($branch))) {
if (is_array($next_branch)) {
array_push($key_stack, $key);
$found = branchTraversing($next_branch, $key_stack, $needle_key);
if (!$found) {
array_pop($key_stack);
}
}
}
} else {
array_push($key_stack, $needle_key);
$found = true;
}
return $found;
}
function getPath(& $array, $needle_key) {
$path = [];
branchTraversing($array, $path, $needle_key);
return $path;
}
$test_keys = [1400, 7300, 7302, 7306, 7314, 666];
foreach ($test_keys as $search_key) {
echo '<p>' . $search_key . ' => [ '
. implode(', ', getPath($array, $search_key)) . ' ]</p>';
}

How do I create a category tree, where subcategories can have multiple parents?

I need create some functions that return an array of categories and subcategories, where subcategories can have more then one parent. I have tried to solve this problem for maybe 6 days but there's nothing on internet.
Here is some code I have created, but it doesn't work.
private function getAllSubs($category, $index, $parent = null)
{
$subs = $this->database->table('eshop_product_categoryo')
->where('parent', $category->id);
$haveSub = false;
foreach($subs as $sub)
{
$haveSub = true;
break;
}
if($haveSub)
{
$mainCategory = $this->database->table('eshop_product_categoryo')
->where('category', $category->id);
$isMainCategory = true;
foreach($mainCategory as $main)
{
$isMainCategory = false;
break;
}
$ppp = 0;
if(!$isMainCategory)
{
$ppp = $parent;
}
$this->someArray[] = array
(
'name' => $category->name,
'parent' => $ppp,
'index' => $index,
'id' => $category->id
);
foreach($subs as $sub)
{
$ctgry = $this->database->table('eshop_product_category')
->where('id', $sub->category)
->fetch();
$this->getAllSubs($ctgry, ($index+1), $sub->parent);
}
}
}
ok finally solved... ;-) here is almost finally version
private function getAllSubs($category, $index)
{
$subs = $this->database->table('eshop_product_categoryo')
->where('otec', $category->id);
$hasSub = false;
foreach($subs as $sub){$hasSub = true; break;}
if($hasSub)
{
$this->someArray[] = array
(
'name' => $category->name,
'index' => $index
);
foreach($subs as $sub)
{
$parent = $this->database->table('eshop_product_category')
->where('id', $sub->category)
->fetch();
$this->getAllSubs($parent, ($index + 1));
}
}
else
{
$this->someArray[] = array
(
'name' => $category->name,
'index' => $index
);
}
}

PHP - Arrays and Foreach

I searched in Google and consulted the PHP documentation, but couldn't figure out how the following code works:
$some='name=Licensing Module;nextduedate=2013-04-10;status=Active|name=Test Addon;nextduedate=2013-04-11;status=Active';
function getActiveAddons($somet) {
$addons = array( );
foreach ($somet as $addon) {
if ($addon['status'] == 'Active') {
$addons[] = $addon['name'];
continue;
}
}
return $addons;
}
echo (count( getActiveAddons( $some ) ) ? implode( '<br />', getActiveAddons( $some ) ) : 'None');
The code always echo's None.
Please help me in this.
I don't know where you got this code from but you've initialized $some the wrong way. It is expected as an array like this:
$some = array(
array(
'name' => 'Licensing Module',
'nextduedate' => '2013-04-10',
'status' => 'Active'
),
array(
'name' => 'Test Addon'
'nextduedate' => '2013-04-11',
'status' => 'Active'
)
);
I guess the article you've read is expecting you to parse the original string into this format.
You can achieve this like this:
$string = 'name=Licensing Module;nextduedate=2013-04-10;status=Active|name=Test Addon;nextduedate=2013-04-11;status=Active';
$result = array();
foreach(explode('|', $string) as $record) {
$item = array();
foreach(explode(';', $record) as $column) {
$keyval = explode('=', $column);
$item[$keyval[0]] = $keyval[1];
}
$result[]= $item;
}
// now call your function
getActiveAddons($result);
$some is not an array so foreach will not operate on it. You need to do something like
$some = array(
array(
'name' => 'Licensing Module',
'nextduedate' => '2013-04-10',
'status' => 'Active'
),
array(
'name' => 'Test Addon',
'nextduedate' => '2013-04-11',
'status'=> 'Active'
)
);
This will create a multidimensional array that you can loop through.
function getActiveAddons($somet) {
$addons = array( );
foreach ($somet as $addon) {
foreach($addon as $key => $value) {
if ($key == 'status' && $value == 'Active') {
$addons[] = $addon['name'];
continue;
}
}
}
return $addons;
}
First, your $some variable is just a string. You could parse the string into an array using explode(), but it's easier to just start as an array:
$some = array(
array(
"name" => "Licensing Module",
"nextduedate" => "2013-04-10",
"status" => "Active",
),
array(
"name" => "Test Addon",
"nextduedate" => "2013-04-11",
"status" => "Active",
)
);
Now, for your function, you are on the right track, but I'll just clean it up:
function getActiveAddons($somet) {
if (!is_array($somet)) {
return false;
}
$addons = array();
foreach ($somet as $addon) {
if ($addon['status'] == 'Active') {
$addons[] = $addon['name'];
}
}
if (count($addons) > 0) {
return $addons;
}
return false;
}
And finally your output (you were calling the function twice):
$result = getActiveAddons($some);
if ($result === false) {
echo "No active addons!";
}
else {
echo implode("<br />", $result);
}

PHP - Adding multiple database entries

I have a function that adds an entry to the database, the code i have at the moment is as follows:
function create_internal_role($rolename, $rolekey)
{
$data = array(
'name' => $rolename,
'key' => $rolekey.'1'
);
if (!is_null($res = $this->ci->internal_roles->create_role($data))) {
return $data;
}
return NULL;
}
What i want to do, is using the same function add another 2 data arrays with a 2 and 3 behind the $rolekey, so that with the one function, it adds 3 lots of data, rolekey1, rolekey2 and rolekey3
How would i go about doing that?
With out knowing about your structure and from the current phrasing of your question, the obvious answer would seem to be this:
function create_internal_role($rolename, $rolekey)
{
$ret = array();
$data = array(
'name' => $rolename,
'key' => $rolekey.'1'
);
if (!is_null($res = $this->ci->internal_roles->create_role($data))) {
$ret[] = $data;
}
$data = array(
'name' => $rolename,
'key' => $rolekey.'2'
);
if (!is_null($res = $this->ci->internal_roles->create_role($data))) {
$ret[] = $data;
}
$data = array(
'name' => $rolename,
'key' => $rolekey.'3'
);
if (!is_null($res = $this->ci->internal_roles->create_role($data))) {
$ret[] = $data;
}
return $ret;
}
If you give more detail in your question, I may be able to give you a better answer.
Perhaps something like this will work:
function create_internal_role($rolename, $rolekey)
{
// define role key indecies
$indexArray = array(1,2,3);
$ret = array(); // return array
// create roles
for(i=0; i<count($indexArray); $i++){
$data = array(
'name' => $rolename,
'key' => $rolekey.indexArray[$i]
);
if (!is_null($res = $this->ci->internal_roles->create_role($data))) {
$ret[] = $data;
}else{
$ret[] = null;
}
}
return $ret;
}

Categories