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 = '';
}
}
}
Related
i have array like this:
(
[0] => Array
(
[id] => 1
[name] => Bazowa
[parent_id] => 0
)
[1] => Array
(
[id] => 2
[name] => Główna
[parent_id] => 1
)
[2] => Array
(
[id] => 12
[name] => PlayStation
[parent_id] => 2
)
[3] => Array
(
[id] => 13
[name] => Xbox
[parent_id] => 2
)
[4] => Array
(
[id] => 14
[name] => Nintendo
[parent_id] => 2
)
[5] => Array
(
[id] => 15
[name] => PC
[parent_id] => 2
)
)
and i want sort this array like tree on screenshot below:
Screen of tree what I want
i trying use this Sort array values based on parent/child relationship
foreach($xml->children()->children() as $value) {
if($value->active == 1) {
$categories[] = [
'id' => (int) $value->id,
'name' => (string) $value->name->language,
'parent_id' => (int) $value->id_parent
];
}
}
$parent_ids = [];
$parents = ['' => []];
foreach($categories as $val) {
$parents[$val['parent_id']][] = $val;
}
$sorted = $parents[''];
dump($parents); exit;
for($val = reset($sorted); $val; $val = next($sorted)) {
if(isset($parents[$val[0]])) {
foreach($parents[$val[0]] as $next) {
$sorted[] = $next;
}
}
}
The most important thing for me is that everything displays well in select, which is something like this:
-Playstation
-- Playstation 5
--- Gry
--Playstation 3
--- Gry
Anyone can help me?
EDIT:
Problem solved by Build a tree from a flat array in PHP
This should work
usort($arr, function($a, $b) {
return $a["parent_id"] > $b["parent_id"];
});
I want to break the below nested array in simple associative array.
Input
Array
(
[0] => Array
(
[id] => 1
[name] => Gadgets
[code] => gadget
[parent_id] =>
[children] => Array
(
[0] => Array
(
[id] => 2
[name] => Mobile
[code] => mobile
[parent_id] => 1
[children] => Array
(
)
)
[1] => Array
(
[id] => 3
[name] => Laptops
[code] => laptop
[parent_id] => 1
[children] => Array
(
[0] => Array
(
[id] => 4
[name] => Dell
[code] => dell
[parent_id] => 3
[children] => Array
(
)
)
[1] => Array
(
[id] => 5
[name] => Lenovo
[code] => lenovo
[parent_id] => 3
[children] => Array
(
)
)
)
)
)
)
)
Output
Array
(
[0] => Array
(
[id] => 1
[name] => Gadgets
[code] => gadget
[parent_id] =>
)
[1] => Array
(
[id] => 2
[name] => Mobile
[code] => mobile
[parent_id] => 1
)
[2] => Array
(
[id] => 3
[name] => Laptops
[code] => laptop
[parent_id] => 1
)
[3] => Array
(
[id] => 4
[name] => Dell
[code] => dell
[parent_id] => 3
)
[4] => Array
(
[id] => 5
[name] => Lenovo
[code] => lenovo
[parent_id] => 3
)
)
Need help in making this type of array from the given array. I tried many things with for loops, but get stuck when in case there are many nested array and that solution does not fit correctly to my requirement.
There is one root node and others are child nodes and many parent nodes can have child nodes.
There are a ton of ways to do this, here are a couple of simple examples. If you don;t care about maintaining order, the recursive function is pretty simple. If you do need to maintain the order of the elements as they are encountered while traversing the tree (to render them as tables for example), it's just a bit more of a faff.
<?php
function flattenTree($array)
{
$output = [];
foreach($array as $currBranch)
{
if(!empty($currBranch['children']))
{
$children = flattenTree($currBranch['children']);
$output = array_merge($output, $children);
}
unset($currBranch['children']);
$output[] = $currBranch;
}
return $output;
}
function flattenTreeMaintainingOrder($array)
{
$output = [];
foreach($array as $currBranch)
{
$children = (array_key_exists('children', $currBranch)) ? $currBranch['children']:[];
unset($currBranch['children']);
$output[] = $currBranch;
if(!empty($children))
{
$children = flattenTreeMaintainingOrder($children);
$output = array_merge($output, $children);
}
}
return $output;
}
$flat = flattenTree($array);
$flatOrdered = flattenTreeMaintainingOrder($array);
print_r($flat) . PHP_EOL;
print_r($flatOrdered) . PHP_EOL;
A recursive function is one option...
function extractChildren($parent, $farr) {
$children = $parent['children'];
if (!$children || count($children)==0) return $farr;
unset($parent['children']);
$farr[]= $parent;
return extractChildren($children, $farr);
}
$finalarray=array();
// $array is the array you have in your question
foreach ($array as $parent) {
$finalarray = extractChildren($parent, $finalarray);
}
As #El_Vanya mentioned above, there are scads of other ways to accomplish this here: How to Flatten a Multidimensional Array?
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,
)
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]
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);