Convert flat array to the multi-dimensional - php

I have an array with tree data (by parent id). I want to convert it to multidimensional array. What is the best way to achieve that? Is there any short function for that?
Source array:
$source = array(
'0' => array(
'Menu' => array(
'id' => 45
'name' => 'Home'
'parent_id' => 1
)
)
'1' => array(
'Menu' => array(
'id' => 47
'name' => 'Get started'
'parent_id' => 1
)
)
'2' => array(
'Menu' => array(
'id' => 72
'name' => 'Attributes'
'parent_id' => 71
)
)
'3' => array(
'Menu' => array(
'id' => 73
'name' => 'Headings'
'parent_id' => 71
)
)
'4' => array(
'Menu' => array(
'id' => 75
'name' => 'Links'
'parent_id' => 71
)
)
'5' => array(
'Menu' => array(
'id' => 59
'name' => 'Images'
'parent_id' => 75
)
)
'6' => array(
'Menu' => array(
'id' => 65
'name' => 'Lists'
'parent_id' => 75
)
)
);
Some parents are missing from the source array. I would like the items with missing parent to be root. Result array:
$result = array(
'0' => array(
'Menu' => array(
'id' => 45
'name' => 'Home'
'parent_id' => 1
)
'Children' => array()
)
'1' => array(
'Menu' => array(
'id' => 47
'name' => 'Get started'
'parent_id' => 1
)
'Children' => array()
)
'2' => array(
'Menu' => array(
'id' => 72
'name' => 'Attributes'
'parent_id' => 71
)
'Children' => array()
)
'3' => array(
'Menu' => array(
'id' => 73
'name' => 'Headings'
'parent_id' => 71
)
'Children' => array()
)
'4' => array(
'Menu' => array(
'id' => 75
'name' => 'Links'
'parent_id' => 71
)
'Children' => array(
'0' => array(
'Menu' => array(
'id' => 59
'name' => 'Images'
'parent_id' => 75
)
'Children' => array()
)
'1' => array(
'Menu' => array(
'id' => 65
'name' => 'Lists'
'parent_id' => 75
)
'Children' => array()
)
)
)
);
Update: removed square brackets.

I don't think there is a built-in function in PHP that does this.
I tried the following code, and it seems to work to prepare the nested array the way you describe:
$nodes = array();
$tree = array();
foreach ($source as &$node) {
$node["Children"] = array();
$id = $node["Menu"]["id"];
$parent_id = $node["Menu"]["parent_id"];
$nodes[$id] =& $node;
if (array_key_exists($parent_id, $nodes)) {
$nodes[$parent_id]["Children"][] =& $node;
} else {
$tree[] =& $node;
}
}
var_dump($tree);
I wrote a similar algorithm in a PHP class I wrote for my presentation Hierarchical Models in SQL and PHP, but I was using objects instead of plain arrays.

I wrote this variant considering root parent_id is 0 or missing. No matter children after parents in DB ($source) or not.
$source_by_id = array();
foreach ($source as &$row){
$source_by_id[$row['id']] = &$row;
}
foreach ($source_by_id as $id => &$row){
$source_by_id[ intval($row['parent_id']) ]['children'][$id] = &$row;
}
// remove cycling itself
unset($source_by_id[0]['children'][0]);
$result = $source_by_id[0]['children'];
Result array keys are appropriate ids. Enjoy!

I was looking for an example of how to do this, with categories. This example assumes that parents will always have a parent id of '0'. The example is using ZF2.
No references, or recursion. The trick is in the output, you look for the [0] index, and for the children, you specify the parent_id as the index.
$categoryLookup = $this->getCategoryLookup($associateById=true);
if ($assignedCategories) {
$categoryHeirarchy = array();
foreach($assignedCategories as $assignedCategory) {
$child = $categoryLookup[$assignedCategory->category_id];
$parent = $categoryLookup[$child->parent_id];
$categoryHeirarchy[$child->parent_id][] = $categoryLookup[$child->category_id];
$categoryHeirarchy[$parent->parent_id][$parent->category_id] = $categoryLookup[$parent->category_id];
}
return $categoryHeirarchy;
}
<h3>Categories</h3>
<dl class="dl-horizontal">
<?php foreach($this->categoryHeirarchy[0] as $parent): ?>
<dt><?php echo $this->escapeHtml($parent->name); ?></dt>
<?php foreach($this->categoryHeirarchy[$parent->category_id] as $child): ?>
<dd><?php echo $this->escapeHtml($child->name); ?></dd>
<?php endforeach; ?>
<?php endforeach; ?>
</dl>

Related

Extract a complete branch from a Parent-Child data structure in PHP using recursion

I have an object from a sql-query. Every entry has the keys (id, type, title, parent_id).
My example data:
Content of the sql-object $list (var_export()):
$array = array(0 => (object) array( 'id' => 1, 'type' => 'label', 'title' => 'Product Categories', 'parent_id' => 0, ),
1 => (object) array( 'id' => 2, 'type' => 'label', 'title' => 'Shoes', 'parent_id' => 1, ),
2 => (object) array( 'id' => 3, 'type' => 'label', 'title' => 'T-Shirts', 'parent_id' => 1, ),
3 => (object) array( 'id' => 4, 'type' => 'label', 'title' => 'With Print', 'parent_id' => 2, ),
4 => (object) array( 'id' => 5, 'type' => 'label', 'title' => 'Without Print', 'parent_id' => 2, ),
5 => (object) array( 'id' => 6, 'type' => 'label', 'title' => 'Brands', 'parent_id' => 2, ),
6 => (object) array( 'id' => 7, 'type' => 'label', 'title' => 'Blue', 'parent_id' => 3, ),
7 => (object) array( 'id' => 8, 'type' => 'label', 'title' => 'Red', 'parent_id' => 3, ));
What i expect:
the function, should find the dependencies of the entries starting with a given id. Here for example the ID 7:
Array
(
[0] => stdClass Object
(
[id] => 7
[type] => "label"
[title] => "Blue"
[parent_id] => 3
)
[1] => stdClass Object
(
[id] => 3
[type] => "label"
[title] => "T-Shirts"
[parent_id] => 1
)
[2] => stdClass Object
(
[id] => 1
[type] => "label"
[title] => "Product Categories"
[parent_id] => 0
)
)
What i get:
I just get an array with the first entry, with the id I started with.
As example with starting ID 7:
array ( 0 => (object) array( 'id' => 7, 'type' => 'label', 'title' => 'Blue', 'parent_id' => 3, ), )
My current Function:
The function needs to search for the item with the given id, stores the information into a new array and then start a new search but with the parent_id as new search id. This should loop as long as there are dependencies, if there are no dependencies the loop should stop and returning the created array.
function getParentSelect($list, $parent) {
$next_id = true;
$result = array();
foreach($list as $k => $s) {
echo $s->id;
if ($s->id == $parent) {
$result[] = $s;
$next_id = $s->parent_id;
break;
}
else {
$next_id = false;
}
}
if ($next_id != false) {
$result = array_merge($result, getParentSelect($list, $next_id));
}
return $result;
}
Recursion is always somewhat difficult to understand. I think you got the main idea, but the execution was flawed. This is what I can up with:
function getParentSelect($list, $select_id) {
$result = [];
foreach($list as $s) {
if ($s->id == $select_id) {
$result = array_merge([$s], getParentSelect($list, $s->parent_id));
}
}
return $result;
}
The assumption here is that all the parent id's are valid.
How does the code work?
The function itself searched the whole list for items with the id that was selected. If it finds one it will add it to the results, but it also looks for any parents of that item. This is where the function recurses. This means that the function can also look for parents of parents, and so on. array_merge() is used to combine the items and all parents together to form the results.

Replace key in array, with keeping order intact

I would like to replace keys in arrays, because I will move them on two indexes up.
Problem that I am facing is that those are containing same names which will not be ok, if i want to move them up.
This is how array looks like.
$list = array(
'ind' => array(
'messagetype' => 'Alert',
'visibility' => 'Public',
'info' => array(
0 => array(
'urgency' => 'Urgent',
'params' => array(
0 => array(
'Name' => 'display',
'value' => '3; top',
),
1 => array(
'Name' => 'level',
'value' => '1; blue',
),
),
'area' => array(
'ard' => 'Bob',
'code' => array(
0 => array(
'Name' => 'Badge',
'value' => 'GSSD154',
),
),
),
),
1 => array(
'messagetype' => 'Information',
'visibility' => 'Private',
'info' => array(
0 => array(
'urgency' => 'Minor',
'params' => array(
0 => array(
'Name' => 'display',
'value' => '1; left',
),
1 => array(
'Name' => 'level',
'value' => '1; red',
),
),
'area' => array(
'ard' => 'Bob',
'code' => array(
0 => array(
'Name' => 'Badge',
'value' => 'GBECS23',
),
),
),
),
),
),
),
),
);
and this is how I would like the output to be with changing keys in Name0, Name1, which are inside params.
$list = array(
'ind' => array(
'messagetype' => 'Alert',
'visibility' => 'Public',
'info' => array(
0 => array(
'urgency' => 'Urgent',
'params' => array(
0 => array(
'Name0' => 'display',
'value0' => '3; top',
),
1 => array(
'Name1' => 'level',
'value1' => '1; blue',
),
),
'area' => array(
'ard' => 'Bob',
'code' => array(
0 => array(
'Name' => 'Badge',
'value' => 'GSSD154',
),
),
),
),
1 => array(
'messagetype' => 'Information',
'visibility' => 'Private',
'info' => array(
0 => array(
'urgency' => 'Minor',
'params' => array(
0 => array(
'Name0' => 'display',
'value0' => '1; left',
),
1 => array(
'Name1' => 'level',
'value1' => '1; red',
),
),
'area' => array(
'ard' => 'Bob',
'code' => array(
0 => array(
'Name' => 'Badge',
'value' => 'GBECS23',
),
),
),
),
),
),
),
),
);
I have tried with a lots of examples over this website, but could not find one to achieve this.
Code that I used from
How to replace key in multidimensional array and maintain order
function replaceKey($subject, $newKey, $oldKey) {
// if the value is not an array, then you have reached the deepest
// point of the branch, so return the value
if (!is_array($subject)) {
return $subject;
}
$newArray = array(); // empty array to hold copy of subject
foreach ($subject as $key => $value) {
// replace the key with the new key only if it is the old key
$key = ($key === $oldKey) ? $newKey : $key;
// add the value with the recursive call
$newArray[$key] = replaceKey($value, $newKey, $oldKey);
}
return $newArray;
}
$s = replaceKey($list, 'Name0', 'Name');
print "<PRE>";
print_r($s);
at the moment I get this output:
[0] => Array
(
[Name0] => display
[value] => 1; left
)
[1] => Array
(
[Name0] => level
[value] => 1; red
)
any help would be appreciated. regards
A very strange question, but why not?
The following function returns nothing (a procedure) and changes the array in-place using references but feel free to rewrite it as a "real" function (without references and with a return statement somewhere).
The idea consists to search for arrays, with numeric keys and at least 2 items, in which each item has the Name and value keys. In other words, this approach doesn't care about paths where the targets are supposed to be:
function replaceKeys(&$arr) {
foreach ($arr as &$v) {
if ( !is_array($v) )
continue;
$keys = array_keys($v);
if ( count($keys) < 2 ||
$keys !== array_flip($keys) ||
array_keys(array_merge(...$v)) !== ['Name', 'value'] ) {
replaceKeys($v);
continue;
}
foreach ($v as $k => &$item) {
$item = array_combine(["Name$k", "value$k"], $item);
}
}
}
replaceKeys($list);
print_r($list);
demo

Remove Child Array If Value of A Key is Duplicate

I want to remove a child array from a multi-dimensional array in case a duplicate value found for a particular key. The answer(s) here didn't work at all. The answer here works, however, for large amount of arrays, that gets pretty slower. Looking for a cleaner and faster solution.
Example PHP Array
$args = array();
$args[] = array(
'section' => array(
'id' => 'section1',
'name' => 'Section 1',
),
'name' => 'Shortcode Name',
'action' => 'shortcodeaction',
'icon' => 'codeicon',
'image' => 'codeimage',
);
$args[] = array(
'section' => array(
'id' => 'section2',
'name' => 'Section 2',
),
'name' => 'Shortcode2 Name',
'action' => 'shortcodeaction2',
'icon' => 'codeicon2',
'image' => 'codeimage2',
);
$args[] = array(
'section' => array(
'id' => 'section3',
'name' => 'Section 3',
),
'name' => 'Shortcode3 Name',
'action' => 'shortcodeaction3',
'icon' => 'codeicon3',
'image' => 'codeimage3',
);
$args[] = array(
'section' => array(
'id' => 'section1',
'name' => 'Section 4',
),
'name' => 'Shortcode4 Name',
'action' => 'shortcodeaction4',
'icon' => 'codeicon4',
'image' => 'codeimage4',
);
$args[] = array(
'section' => array(
'id' => 'section5',
'name' => 'Section 5',
),
'name' => 'Shortcode5 Name',
'action' => 'shortcodeaction5',
'icon' => 'codeicon5',
'image' => 'codeimage5',
);
$sections = array();
foreach ( $args as $arg ) {
$sections[] = $arg['section'];
}
And, the print_r($sections) result.
Array
(
[0] => Array
(
[id] => section1
[name] => Section 1
)
[1] => Array
(
[id] => section2
[name] => Section 2
)
[2] => Array
(
[id] => section3
[name] => Section 3
)
[3] => Array
(
[id] => section1
[name] => Section 4
)
[4] => Array
(
[id] => section5
[name] => Section 5
)
)
Both Array[0] and Array[3] has the same value for the key id, therefor the entire Array[3] has to be removed in my case to avoid duplicates.
This is working for me though, but it gets really slow when there are 100s or more arrays.
$knownIds = array();
foreach( $sections AS $key=>$item ) {
if( array_key_exists($item['id'], $knownIds) === true ) {
unset( $sections[$key] );
} else {
$knownIds[$item['id']] = $key;
}
}
$sections = array_values($sections);
Tried several answers here in StackOverflow (including this), but none of them helped in my case.
Thanks
You can modify the whole using array_column and array_filter -
//get all the sections value
$section = array_column($args, 'section');
//store ids in temp array
$idArray = array_unique(array_column($section, 'id'));
//filter the array having unique id
$uniqueSections = array_filter($section, function ($key, $value) use ($idArray) {
return in_array($value, array_keys($idArray));
}, ARRAY_FILTER_USE_BOTH);
var_dump($uniqueSections);
For PHP <5.5
$section = array_map(function($args) {
return $args['section'];
}, $args);
$idArray = array_unique(array_map(function($section){return $section['id'];}, $section));

How to Create Menu From Array

i have an array from database like this. I want to put the array into a menu like this.
Setting
Menu Category
Menu Category View
Group
Group View
Deposits
Group Menu
Group Menu View
Menu
Menu View
ETC
I've been trying But so far every attempt failed
array(
(int) 0 => array(
'MenuCategory' => array(
'name' => 'Setting'
),
'Menu' => array(
'name' => 'Menu Category',
'url' => '/menu_categories/adding',
'parent_id' => null
),
'Site' => array(
'id' => (int) 1
),
'Sub' => array(
'name' => 'Menu Category View',
'url' => '/menu_categories/view'
)
),
(int) 1 => array(
'MenuCategory' => array(
'name' => 'Setting'
),
'Menu' => array(
'name' => 'Group',
'url' => '/groups/adding',
'parent_id' => null
),
'Site' => array(
'id' => (int) 1
),
'Sub' => array(
'name' => 'Group View',
'url' => '/groups/view'
)
),
(int) 2 => array(
'MenuCategory' => array(
'name' => 'Setting'
),
'Menu' => array(
'name' => 'Deposits',
'url' => '/Deposits/requestTiket',
'parent_id' => null
),
'Site' => array(
'id' => (int) 1
),
'Sub' => array(
'name' => null,
'url' => null
)
),
(int) 3 => array(
'MenuCategory' => array(
'name' => 'Setting'
),
'Menu' => array(
'name' => 'Group Menus',
'url' => '/group_menus/adding',
'parent_id' => null
),
'Site' => array(
'id' => (int) 1
),
'Sub' => array(
'name' => 'Group View',
'url' => '/group_menus/view'
)
),
(int) 4 => array(
'MenuCategory' => array(
'name' => 'Setting'
),
'Menu' => array(
'name' => 'Menu',
'url' => '/menus/adding',
'parent_id' => null
),
'Site' => array(
'id' => (int) 1
),
'Sub' => array(
'name' => 'Menu View',
'url' => '/menus/view'
)
)
);
can anyone help me ? ?
You can simply loop through it with three nested foreach() loops, like so:
$arr = // your array;
echo "<ul>";
foreach($arr as $setting => $nested) {
echo "<li>$setting<ul>";
foreach($nested as $category => $nested2) {
echo "<li>$category</li><ul>";
foreach($nested2 as $view) {
echo "<li>$view</li>";
}
echo "</ul></li>";
}
echo "</ul></li>";
}
echo "</ul>";
The only problem with this is that it might print out unnecessary (empty) <ul>s, and that the <ul>s default to different bullet types (easy to fix with CSS though).
Test it out at PHP Sandbox or at Ideone. Here is the output provided:
<ul><li>setting<ul><li>menu category</li><ul><li>menu category view</li></ul></li><li>group</li><ul><li>group view</li></ul></li><li>deposits</li><ul></ul></li><li>group menu</li><ul><li>group menu array</li></ul></li><li>menu</li><ul><li>menu view</li></ul></li></ul></li></ul>
import java.util.Scanner;
public class ARRAY123 {
static int Yaki2=0;
static String ff, ll;
static Scanner Yaki = new Scanner (System.in);
public static void main (String[]a){
//String [] Names = new Array (5);
char menuInput;
char retry;
String [] names;
names = new String [5];
names [0] = "";
names [1] = "";
names [2] = "";
names [3] = "";
names [4] = "";
do {
System.out.println("Names in the Array");
System.out.println("Choose what you want to do with the Array:");
System.out.println("[A]ADD");
System.out.println("[B]EDIT");
System.out.println("[C]DELETE");
System.out.println("[D]SORT");
System.out.println("[E]SEARCH");
menuInput = Yaki.next().charAt(0);
switch (menuInput) {
case 'a':
case 'A':
System.out.println("Add Elements to the Array");
System.out.print("Input whatever element you want to add:");
add(names);
break;
case 'b':
case 'B':
System.out.println("Edit an Element in the Array");
ll = Yaki.next();
System.out.println("Palitan mo na");
ff = Yaki.next();
wait
(ll,ff);
break;
}
System.out.println("Would you like to do more?");
retry = Yaki.next().charAt(0);
}while (retry == 'Y'|| retry == 'y');
System.out.println(names[0]);
System.out.println(names[1]);
System.out.println(names[2]);
System.out.println(names[3]);
System.out.println(names[4]);
}
private static void wait(String ll2, String ff2) {
// TODO Auto-generated method stub
}
static void add (String a[]) {
if (Yaki2 < a.length) {
a[Yaki2] = Yaki.next();
Yaki2++;}
else
System.out.println("The Elements in the Array are complete, you can no longer add more");
}
}

How to copy this portion of the array to a new array in php?

I have this php array X.
X= array(
'Parent' => array(
'title' => '123',
)
)
I have this php array Y.
Y = array(
'Parent' => array(
'id' => '16',
'title' => 'T1',
),
'Children' => array(
(int) 0 => array(
'id' => '8',
'serial_no' => '1',
),
(int) 1 => array(
'id' => '9',
'serial_no' => '2',
),
(int) 2 => array(
'id' => '14',
'serial_no' => '6',
)
)
)
I want to copy the Children of array Y to the parent of array X to form array Z such that it looks like this;
Z= array(
'Parent' => array(
'title' => '123',
)
'Children' => array(
(int) 0 => array(
'serial_no' => '1'
),
(int) 1 => array(
'serial_no' => '2'
),
(int) 2 => array(
'serial_no' => '6'
)
)
)
Please note that the id key-value pair was removed from the Children of array Y.
I wrote some code of my own.
$Z = array();
$i=0;
foreach($Y as $temp)
{
$Z['Children'][$i] = $temp['Children'][$i];
unset($Z['Children'][$i]['id'];
$i++;
}
$Z['Parent']=$temp['Parent'];
Unfortunately, there is an undefined index error. How can this be done in php? Forget about my code if there are better approaches.
Actually your approach works too, but you need to iterate over sub-array:
$Z = array();
$i=0;
foreach($Y['Children'] as $temp)
{
$Z['Children'][$i] = $temp;
unset($Z['Children'][$i]['id'];
$i++;
}
or what I may do:
$Z = $X;
$Z['Children'] = array();
foreach ( $Y['Children'] as $child ) {
$Z['Children'][] = array(
'serial_no' => $child['serial_no'],
);
}
You can do like.
$Z = array();
foreach($Y['Children'] as $temp)
{
$Z['Children'][] = array('serial_no' => $temp['serial_no']);
}
$Z['Parent']=$X['Parent'];

Categories