PHP: Convert linear array to tree structure array - php

I have an array like bellow
Array
(
[0] => Array
(
[parent_id] => 0
[child_id] => 1
[uuid] => a707aa7f-2180-4cb5-9227-57c948491731
[sdi] =>
[serial] => 03466720000004033
[gs1_id] => urn:epc:id:sscc:0346672.0000004033
[type] => CONTAINER
)
[1] => Array
(
[parent_id] => 1
[child_id] => 2
[uuid] => 5bd9da67-90eb-4fb1-b25a-0f534efd661f
[sdi] => SDI-5bd9da67-90eb-4fb1-b25a-0f534efd661f
[serial] => 100000003718
[gs1_id] => urn:epc:id:sgtin:0369499.232915.100000003718
[type] => PRODUCT
)
[2] => Array
(
[parent_id] => 2
[child_id] => 3
[uuid] => b3224592-0268-4853-8700-03f53e759fa1
[sdi] => SDI-b3224592-0268-4853-8700-03f53e759fa1
[serial] => 100000042535
[gs1_id] => urn:epc:id:sgtin:0369499.032915.100000042535
[type] => PRODUCT
)
)
but I need a tree structure data from the array by using parent_id and child_id and the array size may be 100,000.
How can I do that?

Write a recursive function in order to convert the array from linear to tree. I have written such a function for your use-case.
Look at the following code:
/**
* Recursively sort an array of hierarchically. Childs will be placed under a 'children' member of their parent term.
*/
function sort_array_hierarchically(Array &$linear, Array &$into, $parentId = 0) {
foreach ($linear as $i => $elem) {
if ($elem["parent_id"] == $parentId) {
array_push($into,$elem);
}
}
foreach ($into as $k => $topElem) {
$into[$k]["children"] = [];
sort_array_hierarchically($linear, $into[$k]["children"], $topElem["child_id"]);
}
}
$linear_array = [
["parent_id"=>0,"child_id"=>1,"name"=>"foo"],
["parent_id"=>1,"child_id"=>2,"name"=>"bar"],
["parent_id"=>0,"child_id"=>3,"name"=>"lol"],
["parent_id"=>1,"child_id"=>4,"name"=>"sure"],
["parent_id"=>4,"child_id"=>5,"name"=>"never"],
["parent_id"=>3,"child_id"=>6,"name"=>"never"]
];
$into = [];
sort_array_hierarchically($linear_array,$into);
var_dump($into);
The output looks like this:
array(2) {
[0]=>
array(4) {
["parent_id"]=>
int(0)
["child_id"]=>
int(1)
["name"]=>
string(3) "foo"
["children"]=>
array(2) {
[0]=>
array(4) {
["parent_id"]=>
int(1)
["child_id"]=>
int(2)
["name"]=>
string(3) "bar"
["children"]=>
array(0) {
}
}
[1]=>
array(4) {
["parent_id"]=>
int(1)
["child_id"]=>
int(4)
["name"]=>
string(4) "sure"
["children"]=>
array(1) {
[0]=>
array(4) {
["parent_id"]=>
int(4)
["child_id"]=>
int(5)
["name"]=>
string(5) "never"
["children"]=>
array(0) {
}
}
}
}
}
}
[1]=>
array(4) {
["parent_id"]=>
int(0)
["child_id"]=>
int(3)
["name"]=>
string(3) "lol"
["children"]=>
array(1) {
[0]=>
array(4) {
["parent_id"]=>
int(3)
["child_id"]=>
int(6)
["name"]=>
string(5) "never"
["children"]=>
array(0) {
}
}
}
}
}

Related

PHP how to unset a sub-array by key from a sub-array within a multi dimensional parent array?

I have this array here that contains a group of duplicate ids each id is set as as array key and the sub array contains a list of ids that also has another array within the same array?
DUPLICATES 16
array(16) {
[19503804]=>
array(3) {
[0]=>
string(8) "19501594"
[1]=>
string(8) "15539642"
[2]=>
string(8) "19498944"
}
[19501594]=>
array(3) {
[0]=>
string(8) "19503804"
[1]=>
string(8) "15539642"
[2]=>
string(8) "19498944"
}
[19837033]=>
array(6) {
[0]=>
string(8) "19854557"
[1]=>
string(8) "19854558"
[2]=>
string(8) "19854553"
[3]=>
string(8) "19854565"
[4]=>
string(8) "19854554"
[5]=>
string(8) "19854683"
}
[19854553]=>
array(6) {
[0]=>
string(8) "19854557"
[1]=>
string(8) "19854558"
[2]=>
string(8) "19837033"
[3]=>
string(8) "19854565"
[4]=>
string(8) "19854554"
[5]=>
string(8) "19854683"
}
[19544216]=>
array(3) {
[0]=>
string(8) "19524884"
[1]=>
string(8) "19560234"
[2]=>
string(8) "19540264"
}
[19854565]=>
array(6) {
[0]=>
string(8) "19854557"
[1]=>
string(8) "19854558"
[2]=>
string(8) "19837033"
[3]=>
string(8) "19854553"
[4]=>
string(8) "19854554"
[5]=>
string(8) "19854683"
}
[19854554]=>
array(6) {
[0]=>
string(8) "19854557"
[1]=>
string(8) "19854558"
[2]=>
string(8) "19837033"
[3]=>
string(8) "19854553"
[4]=>
string(8) "19854565"
[5]=>
string(8) "19854683"
}
[15539642]=>
array(3) {
[0]=>
string(8) "19503804"
[1]=>
string(8) "19501594"
[2]=>
string(8) "19498944"
}
[19844271]=>
array(1) {
[0]=>
string(8) "19341140"
}
[19498944]=>
array(3) {
[0]=>
string(8) "19503804"
[1]=>
string(8) "19501594"
[2]=>
string(8) "15539642"
}
[16399898]=>
array(1) {
[0]=>
string(8) "15436391"
}
[15436391]=>
array(1) {
[0]=>
string(8) "16399898"
}
[19341140]=>
array(1) {
[0]=>
string(8) "19844271"
}
[19560234]=>
array(3) {
[0]=>
string(8) "19544216"
[1]=>
string(8) "19524884"
[2]=>
string(8) "19540264"
}
[19854683]=>
array(6) {
[0]=>
string(8) "19854557"
[1]=>
string(8) "19854558"
[2]=>
string(8) "19837033"
[3]=>
string(8) "19854553"
[4]=>
string(8) "19854565"
[5]=>
string(8) "19854554"
}
[19540264]=>
array(3) {
[0]=>
string(8) "19544216"
[1]=>
string(8) "19524884"
[2]=>
string(8) "19560234"
}
}
notice first array?
[19503804]=>
array(3) {
[0]=>
string(8) "19501594"
[1]=>
string(8) "15539642"
[2]=>
string(8) "19498944"
}
the "19501594" "15539642" "19498944" also has another array which need to be unset.so at the end in this array only the unique arrays with unique values are given.
and this is the expected output required.
array(5) {
[19503804]=>
array(3) {
[0]=>
string(8) "19501594"
[1]=>
string(8) "15539642"
[2]=>
string(8) "19498944"
}
[19837033]=>
array(6) {
[0]=>
string(8) "19854557"
[1]=>
string(8) "19854558"
[2]=>
string(8) "19854553"
[3]=>
string(8) "19854565"
[4]=>
string(8) "19854554"
[5]=>
string(8) "19854683"
}
[19544216]=>
array(3) {
[0]=>
string(8) "19524884"
[1]=>
string(8) "19560234"
[2]=>
string(8) "19540264"
}
[19844271]=>
array(1) {
[0]=>
string(8) "19341140"
}
[16399898]=>
array(1) {
[0]=>
string(8) "15436391"
}
}
This is what i had initially coded as proposed by #Dale in the answer below.
$theduplicates = array (
19503804 =>
array (
0 => '19501594',
1 => '15539642',
2 => '19498944',
),
19501594 =>
array (
0 => '19503804',
1 => '15539642',
2 => '19498944',
),
19837033 =>
array (
0 => '19854557',
1 => '19854558',
2 => '19854553',
3 => '19854565',
4 => '19854554',
5 => '19854683',
),
19854553 =>
array (
0 => '19854557',
1 => '19854558',
2 => '19837033',
3 => '19854565',
4 => '19854554',
5 => '19854683',
),
19544216 =>
array (
0 => '19524884',
1 => '19560234',
2 => '19540264',
),
19854565 =>
array (
0 => '19854557',
1 => '19854558',
2 => '19837033',
3 => '19854553',
4 => '19854554',
5 => '19854683',
),
19854554 =>
array (
0 => '19854557',
1 => '19854558',
2 => '19837033',
3 => '19854553',
4 => '19854565',
5 => '19854683',
),
15539642 =>
array (
0 => '19503804',
1 => '19501594',
2 => '19498944',
),
19844271 =>
array (
0 => '19341140',
),
19498944 =>
array (
0 => '19503804',
1 => '19501594',
2 => '15539642',
),
16399898 =>
array (
0 => '15436391',
),
15436391 =>
array (
0 => '16399898',
),
19341140 =>
array (
0 => '19844271',
),
19560234 =>
array (
0 => '19544216',
1 => '19524884',
2 => '19540264',
),
19854683 =>
array (
0 => '19854557',
1 => '19854558',
2 => '19837033',
3 => '19854553',
4 => '19854565',
5 => '19854554',
),
19540264 =>
array (
0 => '19544216',
1 => '19524884',
2 => '19560234',
),
)
foreach($theduplicates as $k => $v){
foreach($v as $d){
if(isset($theduplicates[$d])){
unset($theduplicates[$d]);
}
}
// but it totally cleans theduplicates array
array(0) {
}
For every iteration you want to check they keys that have already been iterated. Therefore you want to keep track of these keys. I would do something like this:
$keys = [];
foreach ($main_array as $k => $set) {
if (in_array($k, $keys)) {
unset($main_array[$k]);
continue;
}
foreach ($set as $val) {
$keys[] = $val;
}
}
var_dump($main_array);
This code will also work, but you have to pass by reference:
foreach ($main_array as &$values) {
foreach ($values as $value) {
if(isset($main_array[$value])) {
unset($main_array[$value]);
}
}
}
If I understand your question (of which I am doubtful) this code should get you on your way
$array = [
0 => [5, 6, 7],
1 => [10],
5 => [10], // to remove
6 => [10], // to remove
7 => [10] // to remove
];
print_r($array);
foreach ($array as $key => $values) {
foreach ($values as $value) {
if(isset($array[$value])) {
unset($array[$value]);
}
}
}
print_r($array);
output..
Array
(
[0] => Array
(
[0] => 5
[1] => 6
[2] => 7
)
[1] => Array
(
[0] => 10
)
[5] => Array
(
[0] => 10
)
[6] => Array
(
[0] => 10
)
[7] => Array
(
[0] => 10
)
)
Array
(
[0] => Array
(
[0] => 5
[1] => 6
[2] => 7
)
[1] => Array
(
[0] => 10
)
)

Create array from array values

I have an array like this :
$lessonOptions=array();
$lessonOptions[0]=array("Physics","6.00","2015-01-01","-","4");
$lessonOptions[1]=array("Physics","16.00","2015-01-01","-","2");
$lessonOptions[2]=array("Maths","10.00","2015-07-01","-","10");
$lessonOptions[3]=array("Maths","20.00","2015-07-01","-","10");
I want to create an output with new array called optionarray which contains:
**
physics 6.00 2015-01-04 -
physics 16.00 2015-01-01 -
maths 10.00 2015-07-01 -
maths 20.00 2015-07-07 -
My problem is that I can see every line of maths but only one line of physics is missing .
How can I display all line ?
My actual code is :
$lessonGroup=$lessonOptions[0][0];
$display=FALSE;
$state=0;
$nbLessons=count($lessonsOptions);
for ($i = 0; $i<$nbLessons; $i++)
{
if ($i+1!=$nbLessons) $lessonGroupSuivant=$lessonOptions[$i+1][0];
else $display=TRUE;
switch ($state)
{
case 0 :
$infoLesson[$state]=$lessonOptions[$i];
default :
{
if ($lessonGroup==$lessonGroupSuivant)
{
$infoLesson[$state]=$lessonOptions[$i];
$state=$state+1;
}
else
{
$display=TRUE;
$lessonGroup=$lessonGroupSuivant;
$state=0;
}
}
}
if ($display==TRUE)
{
//var_dump($infoLesson);
$display=FALSE;
}
}
My actual array (wrong)
As you can see, the size of my array is 1 , I need to have 2 because I have two field for the lesson physics.
array(1) { [0]=> array(5) { [0]=> string(31) "physics" [1]=> string(10) "6.00" [2]=> string(10) "2015-01-01" [3]=> string(1) "-" [4]=> float(42) } }
array(2) { [0]=> array(5) { [0]=> string(15) "Maths" [1]=> string(11) "10.00" [2]=> string(10) "2015-07-01" [3]=> string(1) "-" [4]=> float(10) } [1]=> array(5) { [0]=> string(15) "Maths" [1]=> string(11) "10.00" [2]=> string(10) "2015-07-12" [3]=> string(1) "-" [4]=> float(10) } }
Okay i think i found what you need:
<?php
$lessonOptions=array();
$lessonOptions[0]=array("Physics","6.00","2015-01-01","-","4");
$lessonOptions[1]=array("Physics","16.00","2015-01-01","-","2");
$lessonOptions[2]=array("Maths","10.00","2015-07-01","-","10");
$lessonOptions[3]=array("Maths","20.00","2015-07-01","-","10");
$optionarray = array();
$lastLessonKey = '';
$i = 0;
foreach ($lessonOptions as $key => $data) {
if (empty($lastLessonKey)) {
$lastLessonKey = $data[0];
} else if ($lastLessonKey !== $data[0]) {
$i++;
$lastLessonKey = $data[0];
}
$optionarray[$i][] = $data;
}
var_dump($optionarray);
Output:
array(2) { [0]=> array(2) { [0]=> array(5) { [0]=> string(7) "Physics" [1]=> string(4) "6.00" [2]=> string(10) "2015-01-01" [3]=> string(1) "-" [4]=> string(1) "4" } [1]=> array(5) { [0]=> string(7) "Physics" [1]=> string(5) "16.00" [2]=> string(10) "2015-01-01" [3]=> string(1) "-" [4]=> string(1) "2" } } [1]=> array(2) { [0]=> array(5) { [0]=> string(5) "Maths" [1]=> string(5) "10.00" [2]=> string(10) "2015-07-01" [3]=> string(1) "-" [4]=> string(2) "10" } [1]=> array(5) { [0]=> string(5) "Maths" [1]=> string(5) "20.00" [2]=> string(10) "2015-07-01" [3]=> string(1) "-" [4]=> string(2) "10" } } }
So, you are willing to group arrays by some value
$infoLesson = array();
foreach ($lessonOptions as $v) {
$infoLesson[$v[0]][] = $v;
}
You can then retrieve arrays by key.
For example printing $infoLesson['Maths'] will get you
Array
(
[0] => Array
(
[0] => Maths
[1] => 10.00
[2] => 2015-07-01
[3] => -
[4] => 10
)
[1] => Array
(
[0] => Maths
[1] => 20.00
[2] => 2015-07-01
[3] => -
[4] => 10
)
)
And $infoLesson['Physics']
Array
(
[0] => Array
(
[0] => Physics
[1] => 6.00
[2] => 2015-01-01
[3] => -
[4] => 4
)
[1] => Array
(
[0] => Physics
[1] => 16.00
[2] => 2015-01-01
[3] => -
[4] => 2
)
)

Displaying Array Values from DB

I can`t find a way to loop this structure of array . Anyone does encounter it.?
Print_r output
Array (
[0] => Array ( [0] => [LABOR_NO] => [1] => 3 [WORK_CODE] => 3 [2] => [MHR] => [3] => [PHR] => [4] => [PESO_VALUE] => )
[1] => Array ( [0] => [LABOR_NO] => [1] => 3 [WORK_CODE] => 3 [2] => [MHR] => [3] => [PHR] => [4] => [PESO_VALUE] => )
[2] => Array ( [0] => 1 [LABOR_NO] => 1 [1] => 3 [WORK_CODE] => 3 [2] => 2.50 [MHR] => 2.50 [3] => 0.00 [PHR] => 0.00 [4] => 3000.00 [PESO_VALUE] => 3000.00 )
)
Vardump Output
array(3) {
[0]=> array(10) {
[0]=> NULL ["LABOR_NO"]=> NULL [1]=> string(1) "3" ["WORK_CODE"]=> string(1) "3" [2]=> NULL ["MHR"]=> NULL [3]=> NULL ["PHR"]=> NULL [4]=> NULL ["PESO_VALUE"]=> NULL }
[1]=> array(10) { [0]=> NULL ["LABOR_NO"]=> NULL [1]=> string(1) "3" ["WORK_CODE"]=> string(1) "3" [2]=> NULL ["MHR"]=> NULL [3]=> NULL ["PHR"]=> NULL [4]=> NULL ["PESO_VALUE"]=> NULL }
[2]=> array(10) { [0]=> string(1) "1" ["LABOR_NO"]=> string(1) "1" [1]=> string(1) "3" ["WORK_CODE"]=> string(1) "3" [2]=> string(4) "2.50" ["MHR"]=> string(4) "2.50" [3]=> string(4) "0.00" ["PHR"]=> string(4) "0.00" [4]=> string(7) "3000.00" ["PESO_VALUE"]=> string(7) "3000.00" }
}
Heres what i have done but not working i think. i dont know => has been continues to each that turned them to $keys..
include('MySQLHandler.php');
class Displayer extends MySQLHandler {
public function getTitle($batchNo = NULL,$workCode = NULL){
$this->init();
$STMT="SELECT REC_NO,PARTS_WORKSCOPE FROM RAPID_TEMP_ESTIMATE_V3 WHERE BATCH_NO={$batchNo} AND WORK_CODE={$workCode} AND PARTS_WORKSCOPE_TYPE='Workscope:'";
$DATA=$this->Select($STMT);
// create array of data subjects..
$result = array();
$result['REC_NO'] = $DATA[0]['REC_NO'];
$result['PARTS_WORKSCOPE'] = $DATA[0]['PARTS_WORKSCOPE'];
return $result;
}
public function getTotal($batchNo = NULL,$workCode = NULL){
$this->init();
// par selection
$STMT="SELECT PAR_VALUE FROM RAPID_PAR WHERE PAR_NAME='LABOR_RATE_PER_HOUR'";
$DATA = $this->Select($STMT);
$PAR_VALUE = $DATA[0]['PAR_VALUE'];
// rollup
$STMT="SELECT LABOR_NO,WORK_CODE,MHR,PHR,PESO_VALUE FROM RAPID_TEMP_ESTIMATE_V3 WHERE BATCH_NO={$batchNo} AND WORK_CODE={$workCode} ORDER BY MINOR_WORK_CODE, WORK_CODE_ORDER";
$DATA=$this->Select($STMT);
foreach($DATA as $key=>$value){
foreach($value as $fieldset=>$values){
echo $fieldset.'<br/>';
}
}
}
}
$displayer = new Displayer;
$displayer->getTotal(18,3);

php switch array key with subelement key

I would like to switch the main keys(0,1,2) of an array with a subelement key(user_id).
For example, from this array:
array(3) {
[0]=>
array(3) {
["num_products_user_by_ref"]=>
string(1) "1"
["user_id"]=>
string(2) "77"
["reference"]=>
string(3) "E49"
}
[1]=>
array(3) {
["num_products_user_by_ref"]=>
string(1) "9"
["user_id"]=>
string(3) "526"
["reference"]=>
string(3) "E49"
}
[2]=>
array(3) {
["num_products_user_by_ref"]=>
string(2) "38"
["user_id"]=>
string(3) "346"
["reference"]=>
string(3) "E49"
}
}
I need :
array(952) {
[77]=>
array(2) {
["num_products_user_by_ref"]=>
string(1) "1"
["reference"]=>
string(3) "E49"
}
[526]=>
array(3) {
["num_products_user_by_ref"]=>
string(1) "9"
["reference"]=>
string(3) "E49"
}
[346]=>
array(3) {
["num_products_user_by_ref"]=>
string(2) "38"
["reference"]=>
string(3) "E49"
}
Every user_id could contains more than 1 pair num_products_user_by_ref/reference.
I remember that there is a function to achieve this (ksort?) associated to a custom function to implement.
$out = array();
foreach ($arr as $key => $value){
$out[$value['user_id']]["num_products_user_by_ref"] = $value["num_products_user_by_ref"];
$out[$value['user_id']]["reference"] = $value["reference"];
}
print_r($out);
Your question showed a structure that doesn't seem to fit with your comment "Every user_id could contains more than 1 pair num_products_user_by_ref/reference." So, here's another version that allows for that possibility:
$out = array();
foreach ($arr as $key => $value){
$entry = array("num_products_user_by_ref" => $value["num_products_user_by_ref"],
"reference" => $value["reference"]);
$out[$value['user_id']][] = $entry;
}
Output:
Array
(
[77] => Array
(
[0] => Array
(
[num_products_user_by_ref] => 1
[reference] => E49
)
[1] => Array
(
[num_products_user_by_ref] => 5
[reference] => E49
)
)
[526] => Array
(
[0] => Array
(
[num_products_user_by_ref] => 9
[reference] => E49
)
)
[346] => Array
(
[0] => Array
(
[num_products_user_by_ref] => 38
[reference] => E49
)
)
)
Here's another version for those who don't like traditional loops:
$out = array();
array_walk($arr, function($e, $k) use(&$out){
$entry = array("num_products_user_by_ref" => $e["num_products_user_by_ref"],
"reference" => $e["reference"]);
$out[$e['user_id']][] = $entry;
});

Having trouble with a recursion algo

Okay here is my recursion algo:
public function getCategoryTree($tree,$return = array()) {
foreach ($tree->children as $child) {
if (count($child->children) > 0 )
$return[$tree->name] = $this->getCategoryTree($child, $return);
else
$return[] = $child->name;
}
return $return;
}
Here is a snippet of the data structure I'm trying to traverse
Object(stdClass)#290 (6) {
["category_id"]=>
int(1)
["parent_id"]=>
int(0)
["name"]=>
string(4) "Root"
["position"]=>
int(0)
["level"]=>
int(0)
["children"]=>
array(2) {
[0]=>
object(stdClass)#571 (7) {
["category_id"]=>
int(2)
["parent_id"]=>
int(1)
["name"]=>
string(18) "Root MySite.com"
["is_active"]=>
int(0)
["position"]=>
int(0)
["level"]=>
int(1)
["children"]=>
array(11) {
[0]=>
object(stdClass)#570 (7) {
["category_id"]=>
int(15)
["parent_id"]=>
int(2)
["name"]=>
string(9) "Widgets"
["is_active"]=>
int(1)
["position"]=>
int(68)
["level"]=>
int(2)
["children"]=>
array(19) {
[0]=>
object(stdClass)#566 (7) {
["category_id"]=>
int(24)
["parent_id"]=>
int(15)
["name"]=>
string(16) "Blue widgets"
["is_active"]=>
int(1)
["position"]=>
int(68)
["level"]=>
int(3)
["children"]=>
array(0) {
}
}
<snip....>
I'm trying to get a php data structure like such
categories = array( "Root" =>
array("Root MySite.com" =>
array( "Widgets" =>
// final element is NOT an array
array ("Blue Widgets", "Purple Widgets" ...)
)
)
)
I can't quite seem to get the data structure i'm looking for using my recursive algo. Any help
would be great.
Eventually I'll need to parse it again on the frontend and display it, but another problem for another day...
Have a look at this phpFiddle for a full working example. The only error I found was the $this->getCategoryTree which gave me an Fatal Error Using $this when not in object context. So are you sure the function is within the correct scope?
Updated
I hope this one works. :)
function traverse($root, $return = array()) {
$return[$root->name] = array();
foreach ($root->children as $child) {
if (count($child->children) > 0) {
traverse($child, &$return[$root->name]);
}else {
array_push(&$return[$root->name], $child->name);
}
}
return $return;
}
The output from this is:
Array ( [Root] =>
Array (
[Root MySite.com] =>
Array (
[Widgets] => Array ( [0] => Blue Widget [1] => Purple Widget)
[Gizmos] => Array ( [0] => Blue Gizmos [1] => Purple Gizmos)
)
[FooBar.com] =>
Array (
[Widgets] => Array ( [0] => Blue Widget [1] => Purple Widget)
[Gizmos] => Array ( [0] => Blue Gizmos [1] => Purple Gizmos)
)
)
)
Again, full working example

Categories