Let me explain my problem. I try to generate an array of categories.
Here is my function.
private function recursiveCategoriesTree($id_parent, $level, $categories)
{
$tree = array();
foreach($categories as $categorie)
{
if($id_parent == $categorie['id_parent'])
{
$tree[$level][] = $categorie;
$this->recursiveCategoriesTree($categorie['id_category'], ($level+1), $categories);
}
}
return $tree;
}
When I trace the loop with echo, everything seems to work, all the parent categories and girls are covered, but are not pushed into the array.
Here is the print_r of my categories
array(
[0] => Array
(
[id_category] => 4
[name] => Pièces détachées
[id_parent] => 1
)
[1] => Array
(
[id_category] => 5
[name] => Excavateur
[id_parent] => 4
)
[2] => Array
(
[id_category] => 6
[name] => série 100
[id_parent] => 5
)
[3] => Array
(
[id_category] => 7
[name] => above
[id_parent] => 6
)
[4] => Array
(
[id_category] => 8
[name] => système hydraulique
[id_parent] => 7
)
[5] => Array
(
[id_category] => 9
[name] => série 200
[id_parent] => 5
)
[6] => Array
(
[id_category] => 10
[name] => thru
[id_parent] => 6
)
[7] => Array
(
[id_category] => 11
[name] => Compaction
[id_parent] => 4
)
)
Here is the result of print_r generated
Array(
[0] => Array
(
[0] => Array
(
[id_category] => 5
[name] => Excavateur
[id_parent] => 4
)
[1] => Array
(
[id_category] => 11
[name] => Compaction
[id_parent] => 4
)
)
)
I call my function like that
$tree = $this->recursiveCategoriesTree(4, 0, $categories)
What is the problem ? thank you =)
Either get the return value from your recursive call and push that onto the array, or make a private property of the class called tree and push values onto that instead. You are not passing the variable $tree across recursive function calls.
E.g. if you do this it will work: (EDIT: Fixed... [again])
private $catTree = array();
private $catStartLevel = FALSE;
private function recursiveCategoriesTree($id_parent, $level, $categories) {
if ($this->catStartLevel !== FALSE) $this->catStartLevel = $level;
foreach($categories as $categorie) {
if($id_parent == $categorie['id_parent']) {
$this->catTree[$level][] = $categorie;
$this->recursiveCategoriesTree($categorie['id_category'], ($level+1), $categories);
}
}
if ($this->catStartLevel === $level) {
$tree = $this->catTree;
$this->catTree = array();
$this->catStartLevel = FALSE;
}
return $tree;
}
...however this is not great, because you now have a 'pointless' private property in your class. You would be better to change you array structure, and catch the return values from $this->recursiveCategoriesTree()...
EDIT
Thinking about it, if you really want the array in that structure, you would probably be better to pass the variable to be populated with the array by reference:
private function recursiveCategoriesTree($id_parent, $level, $categories, &$tree) {
foreach($categories as $categorie) {
if($id_parent == $categorie['id_parent']) {
$tree[$level][] = $categorie;
$this->recursiveCategoriesTree($categorie['id_category'], ($level+1), $categories, $tree);
}
}
}
...and then you would call it like this...
$myTree = array();
$obj->recursiveCategoriesTree($id_parent, $level, $categories, $myTree);
print_r($myTree);
recursiveCategoriesTree() returns the $tree, but you're not doing anything with that return value when you're calling the method recursively. You're only storing the $tree returned from the initial call to the method.
Perhaps you want something like this?
$categorie['children'] = $this->recursiveCategoriesTree($categorie['id_category'], ($level+1), $categories);
You should first fetch all the childs of a category, and add them to its array, before appending the category to the tree. Kind of like this:
foreach($categories as $categorie)
{
$categorie['childs'] = $this->recursiveCategoriesTree($categorie['id_category'], ($level+1), $categories);
$tree[$level][] = $categorie;
}
Related
I am an amateur in PHP. I tried a lot of suggestions from here but I didn't get the result I need. I want to get the top parent id of a child. ex. For id=10 top parent is 8. This is the array I get from the database. Thanks in advance.
$events = mysqli_query($dbtmx,"SELECT * FROM tmetrix_events WHERE status='1'");
while($re=mysqli_fetch_assoc($events)){
$array[] = array('id'=>$re['id'],'parent_id'=>$re['parent_id']);
}
And the array I am receiving is
Array
(
[0] => Array
(
[id] => 5
[parent_id] => 0
)
[1] => Array
(
[id] => 6
[parent_id] => 5
)
[2] => Array
(
[id] => 7
[parent_id] => 5
)
[3] => Array
(
[id] => 8
[parent_id] => 0
)
[4] => Array
(
[id] => 9
[parent_id] => 8
)
[5] => Array
(
[id] => 10
[parent_id] => 9
)
)
Now I want to find the top parent or root parent id of the child.
I tried Steverst1 and AymDev's code. But I am getting the result.
You can create a recursive function which will run through all parents until it finds 0 which I assume means there is no parent:
function get_top_parent(int $id, array $list): ?array
{
// Find current item
$key = array_search($id, array_column($list, 'id'));
$item = $list[$key] ?? null;
// Check if item has parent
if (null !== $item && $item['parent_id'] !== 0) {
// recursive call
return get_top_parent($item['parent_id'], $list);
}
// No parent (or no item)
return $item;
}
Tested on 3v4l.org: https://3v4l.org/PPm3K
Assumption that 0 in parent_id means that it is the parent we are looking for. So get the id of it.
$child_id = 10;
$parent = 0;
while ($child_id != 0) {
foreach ($array as $key => $inner_arr) {
$id = $inner_arr['id'];
$parent_id = $inner_arr['parent_id'];
if($id === $child_id){
$child_id = $parent_id;
$parent = $id;
}
}
}
echo $parent; // 8
Demo
This question already has answers here:
How to Flatten a Multidimensional Array?
(31 answers)
Closed 4 years ago.
I have some problems with parent array that contains multiple children array. It will be necessary that the array children, does not contain themselves other children array, but if it is the case, then to raise these array grandchildren at the level of children.
[0] => Array (
[0] => Array (
[name] => ...
[count] => ...
[url] => ...
[html] => ...
)
[1] => Array (
[name] => ...
[count] => ...
[url] => ...
)
[2] => Array (
[1] => Array (
[name] => ...
[count] => ...
[url] => ...
[html] => ...
)
[2] => Array (
[name] => ...
[count] => ...
[url] => ...
)
)
[3] => Array (
[name] => ...
[count] => ...
[url] => ...
)
[4] => Array (
[name] => ...
[count] => ...
[url] => ...
)
);
In the example array["2"] contain 2 array, I want that the 2 array go up one level and so become brothers and not children.
Can you help me please with the right function ?
function transformMultipleArraysTo1(array $multipleArrays = null)
{
$newArray = array();
if (!isArrayEmpty($multipleArrays)) {
foreach ($multipleArrays as $array) {
if (is_array($array)) {
foreach ($array as $singleArray) {
if (is_array($singleArray)) {
$newArray[] = $singleArray;
} else {
continue 2;
}
}
$newArray[] = $array;
}
}
}
return $newArray;
}
Many thanks
I came up with this solution, not the prettiest, but it works.
function RemoveThoseNastyGrandchildren(array $array = NULL){
foreach ($array as $ckey => $child) {
foreach($child as $gckey => $grandchild){
if(is_array($grandchild)){
$array[] = $grandchild;
array_splice($array[$ckey],$gckey);
}
}
}
$length = count($array);
for($i = 0; $i < $length ; $i++){
if(!empty($array[$i][0]) && is_array($array[$i][0])){
array_splice($array,$i,1);
$i = -1;
$length = count($array);
}
}
//print("<pre>".print_r($array,true)."</pre>"); <---- To print it pretty uncomment
return $array;
}
The First Loop:
will iterate through all relatives, looking for the potential grandchildren. If it finds one of these nasty grandchildren it'll append it to their parents, becoming a grandchildren again.
After that we just have to disensamble the former grandchildrens bodies, and that's what ...
The Second Loop does:
It's iterating through the changed array, looking for empty bodies.
Then return the freshly shaped array familytree and whooosh, you got rid of those GCs.
Array
(
[updateCategories] => Array
(
[products] => Array
(
[0] => Array
(
[cat_id] => 3
[position] => 2
[product_id] => 8
)
[1] => Array
(
[cat_id] => 4
[position] => 11
[product_id] => 8
)
[2] => Array
(
[cat_id] => 3
[position] => 4
[product_id] => 39
)
[3] => Array
(
[cat_id] => 4
[position] => 9
[product_id] => 8
)
[4] => Array
(
[cat_id] => 3
[position] => 6
[product_id] => 41
)
[5] => Array
(
[cat_id] => 11
[position] => 7
[product_id] => 8
)
The above array is my output array but I need to get all cat_id of product_id=8. How can I do this?
$newarr = array();
foreach( $arr['updateCategories']['products'] as $myarr)
{
if($myarr['product_id'] == 8)
$newarr[] = $myarr['cat_id'];
}
The simpliest solution is
$result = array();
foreach($yourArray['updateCategories']['products'] as $product)
if($product['product_id] == 8)
$product[] = $product['cat_id'];
where $yourArray is the array which dump you have published.
Try something like this:
$arr = array();
foreach ($products as $key => $value)
{
if($value['product_id'] == 8)
{
$arr[] = $key;
}
}
print_r($arr); // <-- this should output the array of products with key as 8
Use this
foreach($array['updateCategories']['products'] as $product) {
if(isset($product['product_id']) && $product['product_id']==8) {
//do anything you want i am echoing
echo $product['cat_id'];
}
}
You can use array_filter.
function filterProducts($product) {
return ($product['product_id'] == 8);
}
$myProducts = array_filter(
$myArray['updateCategories']['products'],
'filterProducts'
);
Where $myArray is the array displayed in your post.
Can handle this by doing something like this
$matching_products = array();
foreach ($products as $key => $value) {
if($value['product_id'] == 8) {
$matching_products[] = $value['cat_id'];
}
}
which'll leave you with an array of cat ids that have a product id of 8
This should be able to retrieve all of the cat_id's from a given product_id. This function yields an object that can be iterated over to retrieve all the values it contains.
<?PHP
public function GetCatIdsByProductId($productId)
{
foreach($updateCategories=>products as $key=>$product)
{
if (isset($product=>product_id) && $product=>product_id == 8)
{
yield $product=>cat_id;
}
}
}
//Usage
$catIds = GetCatIdsByProductId(8);
var_dump($catIds);
A more generic version of this function can be constructed to retrieve a given key from a comparison on a given property value.
public function GetPropertyByPropertyComparison(array $list, $propRet, $propCompare, $compValue)
{
foreach($list as $key=>$product)
{
if (isset($product=>{$propCompare}) && $product=>{$propCompare} == $compValue)
{
yield $product=>{$propRet};
}
}
}
//usage
$cats = GetPropertyByPropertyComparison($updateCategories=>products, "cat_id", "product_id", 8);
var_dump($cats);
?>
I am trying to write a shoping cart in php and I have a problem with get/set values in multidimentional arrays.
I keep the current order in $_SESSION['basket']. It looks like that:
[basket] => Array
(
[0] => Array
(
[pid] => 3
[name] => Camera
[price] => 200.99
[quantity] => 1
)
[1] => Array
(
[pid] => 5
[name] => Computer
[price] => 320.99
[quantity] => 1
[extras] => Array
(
[0] => Array
(
[pid] => 86
[name] => RAM
[price] => 99
[qty] => 1
)
[1] => Array
(
[pid] => 98
[name] => CD-ROM
[price] => 19.99
[qty] => 1
)
)
)
)
Every item is stored as a subarray. I have a function, which checks if a given item exists in the basket array and returns the path to it. For example, if I want to check for a product with id 98 (CD-Rom), the function returns the following path: 1:extras:1.
I cant figure out how to use the path if I want to get or a set a value in the array. Is it possible to construct the path to an array key, without the use of eval()? I have these functions:
function get_val($array, $path, $key) {
//some code
return eval('return '.$array.$path.$key.';');
}
So, $price = get_val($_SESSION['basket'], $path, 'price'); should return the price for CD-ROM (19.99)
function set_val($array, $path, $key, $value) {
//some code
$str = eval(''.$array.$path.$key.';');
$str = $value;
}
set_val($_SESSION['basket'], $path, 'price', '30'); will set the price for CD-ROM to 30.
Is there a better way for doing this?
Thank you.
Here you go a code I have finetuned some time ago:
function get_val($array,$path) {
for($i=$array; $key=array_shift($path); $i=$i[$key]) {
if(!isset($i[$key])) return null;
}
return $i;
}
function set_val(&$array,$path,$val) {
for($i=&$array; $key=array_shift($path); $i=&$i[$key]) {
if(!isset($i[$key])) $i[$key] = array();
}
$i = $val;
}
See this test example, I believe it is what you are looking for:
$data = array("x"=>array("y"=>array("z"=>"foo")));
echo get_val($data,array("x","y","z")); // foo
set_val($data,array("x","y","u"),"bar"); // $data["x"]["y"]["u"] = "bar";
Yesterday people down voted me because I got this function. And today I hope someone can use it.
Getting values
Below function will return the value of the path you define.
function getPath($path, $array)
{
$path = split(":", $path);
$active = $array;
foreach($path as $key => $part)
{
$active = $active[$part];
}
return $active;
}
$array = array(array(array(array("product" => array( "id" => 12 )))));
// Give the path to the data you want, by keys
echo getPath("0:0:0:product:id", $array);
Which echo's
12
And setting values
function setPath($path, &$array, $mykey, $value)
{
$path = split(":", $path);
$active =& $array;
foreach($path as $key => $part)
{
$active =& $active[$part];
}
$active[$mykey] = $value;
return $active;
}
$array = array(array(array(array("product" => array( "id" => 12 )))));
// Give the path to the data you want, by keys
setPath("0:0:0:product", $array, "price", 100);
print_r($array);
Results:
Array ( [0] => Array ( [0] => Array ( [0] => Array ( [product] => Array ( [id] => 12 [price] => 100 ) ) ) ) )
I want a function that
searches through my array, and
returns all the
children to a specific node. What is
the most appropriate way to do this?
Will recursion be necessary in this case?
I have previously constructed a few quite complex functions that iterates with or without the help of recursion through multi-dimensional arrays and re-arranging them, but this problem makes me completely stuck and I can't just get my head around it...
Here's my array:
Array
(
[1] => Array (
[id] => 1
[parent] => 0
)
[2] => Array (
[id] => 2
[parent] => 1
)
[3] => Array (
[id] => 3
[parent] => 2
)
)
UPDATE:
The output which I want to get. Sorry for the bad example, but I'll blame it on lack of knowledge on how to format the stuff I need to do :)
function getAllChildren($id) {
// Psuedocode
return $array;
}
getAllChildren(1); // Outputs the following:
Array
(
[2] => Array (
[id] => 2
[parent] => 1
)
[3] => Array (
[id] => 3
[parent] => 2
)
)
$nodes = array( 1 => array ( 'id' => 1,
'parent' => 0
),
2 => array ( 'id' => 2,
'parent' => 1
),
3 => array ( 'id' => 3,
'parent' => 2
)
);
function searchItem($needle,$haystack) {
$nodes = array();
foreach ($haystack as $key => $item) {
if ($item['parent'] == $needle) {
$nodes[$key] = $item;
$nodes = $nodes + searchItem($item['id'],$haystack);
}
}
return $nodes;
}
$result = searchItem('1',$nodes);
echo '<pre>';
var_dump($result);
echo '</pre>';
Non-recursive version of the searchItem() function:
function searchItem($needle,$haystack) {
$nodes = array();
foreach ($haystack as $key => $item) {
if (($item['parent'] == $needle) || array_key_exists($item['parent'],$nodes)) {
$nodes[$key] = $item;
}
}
return $nodes;
}
(assumes ordering of the parents/children, so a child node isn't included in the array unless the parent is already there)
<?php
function searchItem($needle)
{
foreach ($data as $key => $item)
{
if ($item['id'] == $needle)
{
return $key;
}
}
return null;
}
?>
Check out the array_walk_recursive() function in PHP:
http://www.php.net/manual/en/function.array-walk-recursive.php