I have multidimensional array. It can be extented upto N- levels. I want to collect only name. Name from child to Parent. For example I need output like this
name => "Sport/Algemeen/techn.sp.ondgd/ondergoed dames/Sport bh"
. Level can be increated upto N numbers.
[categories] => Array
(
[0] => Array
(
[#id] => 1
[name] => 78057 | Sport bh
[parent] => Array
(
[#id] => 2
[name] => 7805 | ondergoed dames
[parent] => Array
(
[#id] => 3
[name] => 780 | techn.sp.ondgd
[parent] => Array
(
[#id] => 4
[name] => Algemeen
[parent] => Array
(
[#id] => 5
[name] => Sport
)
)
)
)
)
)
$arrPush = array();
function iterator($arr){
global $arrPush;
foreach($arr as $key => $val){
if(is_array($val))
iterator($val);
if($key == "name"){
$str = explode("|", $val);
$arrPush[] = isset($str[1])?$str[1]:$str[0];
}
//filter the $key and $val here and do what you want
}
}
iterator($sweet);
$str = implode("/", array_reverse($arrPush));
echo $str;
Sport/Algemeen/ techn.sp.ondgd/ ondergoed dames/ Sport bh
Like that (haven't tested)
function namify($arr) {
foreach($arr as $cat) {
if(!empty($cat['parent']) && is_array($cat['parent'])) {
return $cat['name'].namify($cat['parent']);
} else {
return $cat['name'];
}
}
}
echo namify($categories);
Related
I have a vendor data array listed as a tree structure and each vendor have a type.
These are types of vendor and its id:
Agency = 1
Branch Agency = 2
Wholsaler = 3
Smartshop = 4
Example: ['type']=>2 (here this vendor is a branch agency).
My question is: How can I get the count of Branch agencies are in this array, same count of wholesaler and smart shop?
Desired result:
[2 => 2, 3 => 2, 4 => 1]
Here is my dynamic generated array:
Array
(
[2] => Array
(
[id] => 2
[type] => 2
[name] => R-1 Agency
[parent] => 1
[children] => Array
(
[3] => Array
(
[id] => 3
[type] => 3
[name] => R-1-W-1
[parent] => 2
[children] => Array
(
[11] => Array
(
[id] => 11
[type] => 4
[name] => mdf,lk
[parent] => 3
[children] => Array
(
)
)
)
)
)
)
[38] => Array
(
[id] => 38
[type] => 2
[name] => sndflk
[parent] => 1
[children] => Array
(
[40] => Array
(
[id] => 40
[type] => 3
[name] => new one
[parent] => 38
[children] => Array
(
)
)
)
)
)
I used this function :
function take_types($array){
foreach ($array as $key => $value) {
$types[] = $value['type'];
if(!empty($value['children'])){
$this->take_types($value['children']);
}
}
return $types;
}
When I use the above function the output is like this:
Array
(
[0] => 2
[1] => 2
)
I only get two values, I need to get the count of each vendor type.
There will be many techniques to recursively process your tree data. I'll offer a native function style and a custom recursive style.
array_walk_recursive() visits all of the "leaf nodes", so you only need to check the key and push the value into a variable which can be accessed outside of that function's scope -- this is why "modifying by reference" is vital.
Code: (Demo)
// I removed the chunky $tree declaration from my post, see the demo
$result = [];
array_walk_recursive(
$tree,
function($v, $k) use (&$result) {
if ($k === 'type') {
$result[] = $v;
}
}
);
var_export(array_count_values($result));
Or
function recursiveTypeCount($array, $output = []) {
foreach($array as $item) {
if (!isset($output[$item['type']])) {
$output[$item['type']] = 1;
} else {
++$output[$item['type']];
}
if ($item['children']) {
$output = recursiveTypeCount($item['children'], $output);
}
}
return $output;
}
var_export(recursiveTypeCount($tree));
Both will display:
array (
2 => 2,
3 => 2,
4 => 1,
)
I am getting the rows from database and i am trying to generate an array of the parent categories and its children categories (children can also have children), so that i can pass that array data to my smarty template view and can render check boxes with each category and sub category.
Table Categories:
id | name | parent_id
1 | Electronics | 0
2 | Mobile | 1
3 | iPhone | 2
4 | Men | 0
5 | Shirt | 4
I want the result in such way that those categories with parent_id = 0 becomes parent and show nested children below it: like this below
Array (
[0] => Array (
[id] => 1
[name] => Electronics
[children] => Array (
[0] => Array (
[id] => 2
[name] => Mobile
[children] => Array (
[0] => Array (
[id] => 3
[name] => iPhone
)
)
)
)
[1] => Array (
[id] => 4
[name] => Men
[children] => Array (
[0] => Array (
[id] => 5
[name] => Shirt
)
)
)
And this is the code i have written so far:
$parentCat = Shopware()->Db()->query("SELECT * FROM `categories`");
$cats = [];
foreach ($parentCat->fetchAll() as $key => $value) {
$prevId = $value['parent_id'];
if ($prevId == 0) {
$data = [
'id' => $value['id'],
'name' => $value['name']
];
array_push($cats, $data);
} else {
foreach ($cats as $cat) {
if($value['parent_id'] == $cat['id']) {
$childData = [
'id' => $value['id'],
'name' => $value['name'],
];
array_push($cats,$childData);
}
}
}
}
print_r($cats);
die();
The Result I am getting is like this:
Array
(
[0] => Array
(
[id] => 1
[name] => Electronics
)
[1] => Array
(
[id] => 2
[name] => Mobile
)
[2] => Array
(
[id] => 3
[name] => iPhone
)
[3] => Array
(
[id] => 4
[name] => Cars
)
[4] => Array
(
[id] => 5
[name] => Toyota
)
)
Please help.
You can use recursive function like this:
function addToArr(&$arr, $data) {
if ($data["parent_id"] == 0)
return $arr[] = ["id" => $data["id"], "name" => $data["name"], "children"=> []];
foreach($arr as &$e) {
if ($e["id"] == $data["parent_id"]) { // if found add as child
$e["children"][] = ["id" => $data["id"], "name" => $data["name"], "children"=> []];
break;
}
addToArr($e["children"], $data); // call recursively
}
}
Live example: 3v4l
Edit
To have HTML tag:
function getHTMLformat($arr) {
if (!$arr) return "";
$str = "<ul>" . PHP_EOL; // starting the list
foreach ($arr as $e) {
$str .= "<li>" . $e["name"] . getHTMLformat($e["children"]) . "</li>" . PHP_EOL;
}
return $str . "</ul>" . PHP_EOL; // end list
}
echo getHTMLformat($res);
How can I create a function to display an array as a tree. For example I want to obtain a decision tree which I want to walk until I get to the leafs based on the branch's values. I create the tree like bellow:
$tree= new DS_Tree();
$node=array('name' => 'start');
$tree->insert_node($node);
$tree->goto_root();
$mytree = new id3();
$mytree->init($data_array_AttrList,$data_array_values,$data_class,$data_array_instances,$tree);
$mytree->run();
echo '<pre class="brush: php">';
print_r($mytree->tree->draw_tree());
echo '</pre>';
The function draw_tree() is:
public function draw_tree() {
return $this->nodes;
}
The function that creates my tree is:
private function make_tree($attr) {
foreach($this->Values[$attr] as $v) {
$subset = $this->get_subset($attr, $v);
if($the_class = $this->has_same_class($subset)) {
$node =array(
'name' => $attr,
'arc' => $v
);
$this->tree->insert_node($node);
$this->Instance = array_diff_key($this->Instance, $subset);
} else {
$node =array(
'name' => $this->Classa,
'arc' => $v
);
$unresolved = $this->tree->insert_node($node);
}
}
if (isset($unresolved)) {
$this->tree->goto_index($unresolved);
}
}
}
The result is:
Array
(
[0] => Array
(
[name] => Time
[parent] =>
[children] => Array
(
[0] => 1
)
)
[1] => Array
(
[name] => Focus
[arc] => Array
(
[0] => 2 day/week
[1] => 3 day/week
[2] => 4 day/week
[3] => 5 day/week
[4] => 6 day/week
)
[parent] => 0
[children] => Array
(
[0] => 2
)
)
[2] => Array
(
[name] => Dificulty
[arc] => Array
(
[0] => Weght loss
[1] => Mantain weight
[2] => Gain Mass
)
[parent] => 1
[children] => Array
(
[0] => 3
)
)
[3] => Array
(
[name] => Sex
[arc] => Array
(
[0] => Beginner
[1] => Intermediar
[2] => Advance
)
[parent] => 2
[children] => Array
(
[0] => 4
)
)
[4] => Array
(
[name] => Array
(
[Exercise] => Array
(
[0] => Array
(
[0] => Ex1
[1] => Ex2
[2] => Ex3
[3] => Ex4
[4] => Ex5
)
)
)
[arc] => Array
(
[0] => F
[1] => M
)
[parent] => 3
)
)
Just to display an array as a tree:
echo "<pre>";
var_dump($array);
echo "</pre>";
Here is a way to iterate through this data structure and look for a certain value:
function recurseFind($tree, $find, $path = "") {
if (!is_array($tree)) {
// it is a leaf:
if ($tree === $find) {
return $path; // return path where we found it
}
return false;
}
foreach($tree as $key => $value) {
$result = recurseFind($value, $find, $path . (is_numeric($key) ? "[$key]" : "['$key']"));
if ($result !== false) return $result;
}
return false;
}
For the sample input you provided, if you would call it like this:
echo recurseFind($tree, "Mantain weight", '$tree');
Outputs the "location" of that value (first match only) in a format that can be evaluated in PHP:
$tree[2]['arc'][1]
my array is looking like
Array
(
[0] => Array
(
[id] => 1
[parent_id] => 0
[title] => Mobiles & Tablets
[childs] => Array
(
[0] => Array
(
[id] => 10
[parent_id] => 1
[title] => Mobile Phone
)
)
)
[1] => Array
(
[id] => 5
[parent_id] => 0
[title] => Mobile Phones
[childs] => Array
(
[0] => Array
(
[id] => 2
[parent_id] => 5
[title] => Moto G
[childs] => Array
(
[0] => Array
(
[id] => 3
[parent_id] => 2
[title] => Android
)
)
)
[1] => Array
(
[id] => 4
[parent_id] => 5
[title] => Iphone
)
)
)
[2] => Array
(
[id] => 6
[parent_id] => 0
[title] => test
)
[3] => Array
(
[id] => 7
[parent_id] => 0
[title] => Men's Fashion
[childs] => Array
(
[0] => Array
(
[id] => 12
[parent_id] => 7
[title] => Clothing
[childs] => Array
(
[0] => Array
(
[id] => 8
[parent_id] => 12
[title] => Jeans
)
)
)
)
)
[4] => Array
(
[id] => 9
[parent_id] => 0
[title] => test
)
)
i write php code for extract Array.
public $string = '';
public $result = array();
public function getCategoryListsTree( array $items ){
$this->createCategoryExtractNode($items);
echo '<pre>';
print_r($this->result);
exit;
}
public function createCategoryExtractNode(array $items)
{
foreach ($items as $key => $value) {
$this->string .= $value['title'].' > ';
if(isset($value['childs'])){
$this->string .= $this->createCategoryExtractNode($value['childs']);
}else{
$this->result[$value['id']] = trim($this->string,' > ');
$this->string = '';
}
}
}
The Output is
Array
(
[10] => Mobiles & Tablets > Mobile Phone
[3] => Mobile Phones > Moto G > Android
[4] => Iphone
[6] => test
[8] => Men's Fashion > Clothing > Jeans
[9] => test
)
I want output like
Array
(
[10] => Mobiles & Tablets > Mobile Phone
[3] => Mobile Phones > Moto G > Android
[4] => Mobile Phones > Iphone
[6] => test
[8] => Men's Fashion > Clothing > Jeans
[9] => test
)
please help
Thanks
Globals are evil, even if they are wrapped in a fancy OO style. $string is a local context for each createCategoryExtractNode invocation. This does the job:
public $result = array();
public function getCategoryListsTree( array $items ){
$this->createCategoryExtractNode($items);
echo '<pre>';
print_r($this->result);
exit;
}
public function createCategoryExtractNode(array $items, $carrier='')
{
foreach ($items as $key => $value) {
$string = $carrier . $value['title'].' > ';
if(isset($value['childs'])){
$this->createCategoryExtractNode($value['childs'], $string);
}else{
$this->result[$value['id']] = trim($string,' > ');
}
}
}
You need to keep current path in each moment, so lets add a respective property instead of string in your class definition:
public $path = [];
We push an element to path array on entering and pop array in the end. So path property array keeps current path to item. Path items are glued with ' > ' when reaching leaf node:
public function createCategoryExtractNode(array $items)
{
foreach ($items as $key => $value) {
array_push($this->path, $value['title']);
if (isset($value['childs'])) {
$this->string .= $this->createCategoryExtractNode($value['childs']);
} else {
$this->result[$value['id']] = implode(' > ', $this->path);
}
array_pop($this->path);
}
}
This also gets the job done:
public function createCategoryExtractNode(array $items, $breadcrumbs = array(), $level = 0)
{
foreach ($items as $key => $value) {
$breadcrumbs[$level] = $value['title'].' > ';
if(isset($value['childs'])){
$this->createCategoryExtractNode($value['childs'], $breadcrumbs, $level+1);
}else{
$this->string = implode('',$breadcrumbs);
$this->result[$value['id']] = trim($this->string,' > ');
$this->string = '';
}
}
}
I have a problem with my recursional function. May be you can help me.
My function below:
function showTree($items, $level = 0) {
$arr = [];
foreach ($items as $item) {
$arr[] = str_repeat(":", $level * 2) . $item['name'] . "<br />";
if (!empty($item['children'][0])) {
$level++;
$arr[] = $this->showTree($item['children'], $level);
}
}
return $arr;
}
And this generate the output:
Array
(
[0] => Category1
[1] => Array
(
[0] => ::SubCategory2
[1] => ::SubCategory1
[2] => Array
(
[0] => ::::SubSubCategory
)
)
)
But I need a little bit other data as my output:
Array
(
[0] => Category1
[1] => ::SubCategory2
[2] => ::SubCategory1
[3] => ::::SubSubCategory
)
Where is my mistake? Thanks!
P>S:
Input:
Array
(
[0] => Array
(
[id] => 1
[name] => Category1
[parent] => 0
[children] => Array
(
[0] => Array
(
[id] => 4
[name] => SubCategory2
[parent] => 1
[children] => Array
(
)
)
[1] => Array
(
[id] => 2
[name] => SubCategory1
[parent] => 1
[children] => Array
(
[0] => Array
(
[id] => 3
[name] => SubSubCategory
[parent] => 2
[children] => Array
(
)
)
)
)
)
)
)
Change this line:
$arr[] = $this->showTree($item['children'], $level);
to:
$arr = array_merge($arr, $this->showTree($item['children'], $level));
I.e. don't add the array returned while walking the children as a new value into the current array but append the values from it to the current array.
Try this:
function showTree($items, $level = 0, &$arr = array()) {
foreach ($items as $item) {
$arr[] = str_repeat(":", $level * 2) . $item['name'] . "<br />";
if (!empty($item['children'][0])) {
$level++;
$this->showTree($item['children'], $level, $arr);
}
}
return $arr;
}