Generate multi dimensional array from list string - php

I'd like to generate a multi-dimensional array in PHP from the following -
- Item 1
-- Item 1.1
-- Item 1.2
--- Item 1.2.1
--- Item 1.2.2
---- Item 1.2.2.1
- Item 2
- Item 3
- Item 4
-- Item 4.1
-- Item 4.2
My eventual aim is to convert this string into an unordered list.
I'd imagine the best way to do this would be to create a recursive function. On a good day I'm sure I could work this out but I'm having a bit of a mind blank!
The array structure should be something like the below dump -
array(6) {
[0]=>
string(6) "Item 1"
[1]=>
array(3) {
[0]=>
string(8) "Item 1.1"
[1]=>
string(8) "Item 1.2"
[2]=>
array(3) {
[0]=>
string(10) "Item 1.2.1"
[1]=>
string(10) "Item 1.2.2"
[2]=>
array(1) {
[0]=>
string(12) "Item 1.2.2.1"
}
}
}
[2]=>
string(6) "Item 2"
[3]=>
string(6) "Item 3"
[4]=>
string(6) "Item 4"
[5]=>
array(2) {
[0]=>
string(8) "Item 4.1"
[1]=>
string(8) "Item 4.2"
}
}
Hope you can help.

The following will convert straight into HTML without recursion:
$text = array();
$text[] = '- Item 1';
$text[] = '-- Item 1.1';
$text[] = '-- Item 1.2';
$text[] = '--- Item 1.2.1';
$text[] = '--- Item 1.2.2';
$text[] = '---- Item 1.2.2.1';
$text[] = '- Item 2';
$text[] = '- Item 3';
$text[] = '- Item 4';
$text[] = '-- Item 4.1';
$text[] = '-- Item 4.2';
$previous_dash_count = 0; // topmost parent
foreach ($text as $line) {
if (preg_match('/(^\-+)(.*)/', $line, $matches, PREG_OFFSET_CAPTURE)===1) {
$dash_count = strlen($matches[1][0]);
$title = $matches[2][0];
if ($dash_count == $previous_dash_count) {
echo "<li>$title</li>\n";
} elseif ($dash_count > $previous_dash_count) {
echo str_repeat("<ul>\n", $dash_count - $previous_dash_count);
echo "<li>$title</li>\n";
} else {
echo str_repeat("</ul>\n",$previous_dash_count-$dash_count+1);
echo "<ul>\n";
echo "<li>$title</li>\n";
}
$previous_dash_count = $dash_count;
}
}
echo str_repeat("</ul>\n",$previous_dash_count);
I make several assumptions. That the input text always behaves well and doesn't contain randomness. Also I don't assume UTF-8 text, but you're safe with dashes.
Here is the array version in all its gory glory:
$stack = array();
$previous_dash_count = 0;
$parent_node = array();
foreach ($text as $line) {
if (preg_match('/(^\-+)(.*)/', $line, $matches, PREG_OFFSET_CAPTURE)===1) {
$dash_count = strlen($matches[1][0]);
$title = $matches[2][0];
if ($dash_count == $previous_dash_count) {
$parent_node[] = $title;
} elseif ($dash_count > $previous_dash_count) {
for ($push_count = $previous_dash_count; $push_count<$dash_count; $push_count++) {
array_push($stack, $parent_node); // remember node
$new_child = array();
$new_child[] = $title;
$parent_node[] = $new_child;
$parent_node = $new_child;
}
} else {
for ($pop_count = $previous_dash_count; $pop_count >$dash_count; $pop_count--) {
$old_child = $parent_node;
$parent_node = array_pop($stack);
$parent_node[] = $old_child;
}
$parent_node[] = $title;
}
$previous_dash_count = $dash_count;
}
}
for ($pop_count = $previous_dash_count; $pop_count > 0; $pop_count--) {
$old_child = $parent_node;
$parent_node = array_pop($stack);
$parent_node[] = $old_child;
}
print_r($parent_node);
We keep a stack of array nodes, so we have a link between a child and its parent. Note the structure of this code is identical to that for the straight HTML version.

Related

How to echo data from a Multi-Dimensional Array in PHP?

I need to echo/return the data to the page like this:
Catalog: 251-2010
Gauge: 20g
Length: 10cm
Tip Size: 10mm
Here is the array called $vararray. It contains several different arrays of product variation data:
array(3) {
[0]=> array(1) {
["251-2010"]=> array(1) {
["Gauge"]=> string(3) "20g"
}
}
[1]=> array(1) {
["251-2010"]=> array(1) {
["Length"]=> string(4) "10cm"
}
}
[2]=> array(1) {
["251-2010"]=> array(1) {
["Tip Size"]=> string(4) "10mm"
}
}
}
array(3) {
[0]=> array(1) {
["600-VR1620"]=> array(1) {
["Chart Type"]=> string(14) "Shirt"
}
}
[1]=> array(1) {
["600-VR1152"]=> array(1) {
["Chart Type"]=> string(13) "Trousers"
}
}
[2]=> array(1) {
["600-VR16211"]=> array(1) {
["Chart Type"]=> string(13) "Socks"
}
}
}
I need something like this:
$vargroup = array();
foreach ($vararray as $vitems) {
$varmeta = array_values($vararray);
foreach ($varmeta as $metain => $vardetails) {
vargroup[$metain]['catalog'] = $vardetails['Catalog'];
vargroup[$metain]['gauge'] = $vardetails['Gauge'];
vargroup[$metain]['length'] = $vardetails['Length'];
vargroup[$metain]['tipsize'] = $vardetails['Tip Size'];
}
$vars_profile = '';
foreach ($vargroup as $vgrp) {
$vars_profile .= $vgrp[catalog] . '<br>' . $vgrp[gauge] . '<br>' . $vgrp[length] . '<br>' . $vgrp[tipsize];
}
}
return $vars_profile;
I'm having a lot of trouble getting it right. Here is how I need it to look:
Catalog: 251-2010
Gauge: 20g
Length: 10cm
Tip Size: 10mm
Catalog: 600-VR1620
Chart Type: Shirt
Catalog: 600-VR1152
Chart Type: Trousers
Catalog: 600-VR16211
Chart Type: Socks
You can't get all of Catalog, Gauge, Length, and Tip Size from the same $vardetails element, they're in different elements of the array. You need to drill into each element to get its key and value.
You can create $vars_profile in the loop that's processing the original array, you don't need $vargroup.
To show the category only once, use a variable to hold the last value. Only output the category line when this field changes.
$vars_profile = '';
$last_metain = null;
foreach ($vararray as $vitem) {
foreach ($vitem as $metain => $vardetails) {
if ($metain != $last_metain) {
$vars_profile .= "<p>\nCatalog: $metain<br>\n";
$last_metain = $metain;
}
foreach ($vardetails as $key => $value) {
$vars_profile .= "$key: $value<br>\n";
}
}
}
return $vars_profile;

PHP duplicates in nested multidimensional array to combine certain value

The desired output is to have:
{"userId":1,"email":"example#email.com","first":"Tyler","last":"Kanz","groups":[{"groupId":"1","groupName":"GROUP A","groupRoles":["1", "3"]},{"groupId":"2","groupName":"GROUP B","groupRoles":["2"]}]}
Which would compare the Group IDs and combine duplicates with their Group Roles.
I have tried using,
foreach ($groups as $group) {
if ($group['groupId'] == $group_id) {
array_push($group['groupRoles'], $group_role);
//And then unsetting the array
}
It is just adding all of the Groups/Roles into the Group array onto the Groups Array.
array(3) { ["groupId"]=> string(1) "1" ["groupName"]=> string(5)
"GROUP A" ["groupRoles"]=> array(1) { [0]=> string(1) "1" } } array(3) {
["groupId"]=> string(1) "2" ["groupName"]=> string(10) "GROUP B"
["groupRoles"]=> array(1) { [0]=> string(1) "2" } } array(3) {
["groupId"]=> string(1) "1" ["groupName"]=> string(5) "GROUP A"
["groupRoles"]=> array(1) { [0]=> string(1) "3" } }
{"userId":1,"email":"example#email.com","first":"Tyler","last":"Kanz","groups":[{"groupId":"1","groupName":"IRISS","groupRoles":["1"]},{"groupId":"2","groupName":"GROUP B","groupRoles":["2"]},{"groupId":"1","groupName":"GROUP A","groupRoles":["3"]}]}
foreach ($groupmeta as $value) {
$group_roles = array();
$array = unserialize($value['property_value']);
if ($array[0] == $user_ID) {
//Gets Group ID and Role
$group_id = $value['group_id'];
$group_role = $array[1];
$exists = false;
$group_name_q= json_decode(json_encode($wpdb->get_results($wpdb->prepare('SELECT group_name FROM groups WHERE id=%s', $group_id))), true);
$group_name = $group_name_q[0]['group_name'];
echo $group_role;
echo '<br>';
$group_roles[] = $group_role;
$group_info = array(
'groupId'=>$group_id,
'groupName'=>$group_name,
'groupRoles'=>$group_roles,
);
$groups[] = $group_info;
}
}
$sorted_groups = array();
echo '<br>';
}
$return_arr = array(
"userId"=>$user_ID,
"email"=>$user_email,
"first"=>$user_first,
"last"=>$user_last,
"groups"=>$groups
);
echo json_encode($return_arr);
//var_dump($groupmeta_value);
}
Found an answer, FOREACH runs as a cloned object.
Instead I used the following FOR loop and got the desired results.
$found_group = false;
for ($i = 0; $i < count($groups); $i++) {
if ($groups[$i]['groupId'] == $group_id) {
array_push($groups[$i]['groupRoles'], $group_role);
$found_group = true;
}
}
if (!$found_group) {
//Group Name
$group_name_q= json_decode(json_encode($wpdb->get_results($wpdb->prepare('SELECT group_name FROM groups WHERE id=%s', $group_id))), true);
$group_name = $group_name_q[0]['group_name'];
$group_roles[] = $group_role;
$group_info = array(
'groupId'=>$group_id,
'groupName'=>$group_name,
'groupRoles'=>$group_roles,
);
$groups[] = $group_info;
}

PHP find similar ID's (EAN codes) and show if excist

I have a database with different kind of products that have similar ID's (EAN codes). I'm trying to print a list of all similar codes so I can import them and connect them to the same product.
Example:
Product Y has ID 190198001795 and 0190198001795
Product X has ID 190198001780, 0190198001780 and 00190198001780
What I'm trying to achieve:
190198001795 - 0190198001795
190198001795 - 0190198001780 - 00190198001780
What did I try:
Create a foreach to 'group' the similar ID's, but eventually this may corrupt the correct groups.
<?
// GET ALL PRODUCT ID's
$sql = "SELECT * FROM `products`";
$result = $mysqli->query($sql);
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
// Total Downloads - Thousand sperator
$shopID = $row["id"];
$EAN = $row["ean"];
$sqlDouble = "SELECT * FROM `products` WHERE `EAN` IN ('$EAN','0$EAN','00$EAN','000$EAN') LIMIT 200";
$resultDouble = $mysqli->query($sqlDouble);
if ($resultDouble->num_rows > 1) {
// output data of each row
while($row = $resultDouble->fetch_assoc()) {
$EAN = $row["ean"];
$shopID = $row["id"];
$children[] = $EAN;
}
}
}
}
foreach (array_chunk($children, 2, true) as $array) {
echo '<div>';
foreach($array as $kicks) {
echo $kicks." ";
}
echo '</div>';
}
?>
Is there another way to parse trough my rows and check / combine similar ID's?
Try this. See comments for explanation. Outputs:
array(2) {
[190198001780]=>
array(2) {
[2]=>
string(13) "0190198001780"
[8]=>
string(14) "00190198001780"
}
[1234]=>
array(2) {
[5]=>
string(5) "01234"
[6]=>
string(6) "001234"
}
}
Code:
<?php
$eans = ['190198001780', '8715839583923', '0190198001780', '015839583923', '1234', '01234', '001234', '001235', '00190198001780'];
foreach ($eans as $ean)
{
// For all EANs that do not have a leading zero, try to find
// similar ones by looking for the same code with one or more leading
// zeroes.
if ($ean[0] !== '0' && ctype_digit($ean))
{
// Look for any occurrences of this EAN with one or more (+) leading zeroes.
// If no similar EANs found, then don't record any.
if ($matches = preg_grep('/[0]+' . $ean . '/', $eans))
$children[$ean] = $matches;
}
}
var_dump($children);
/*
array(2) {
[190198001780]=>
array(2) {
[2]=>
string(13) "0190198001780"
[8]=>
string(14) "00190198001780"
}
[1234]=>
array(2) {
[5]=>
string(5) "01234"
[6]=>
string(6) "001234"
}
}
*/

Adding rows spanning multiple rows in Symfony Console

I am currently developing a CLI using Symfony Console and I have run into a problem regarding adding a row spanning multiple rows.
My code is
$table = new Table($output);
$table->setHeaders(['Elements','Properties']);
foreach($elements as $key => $element) {
if ($key != 'templates') {
//process element
$rowcount = 0;
foreach($element as $name => $component){
if(is_string($component)){
$strings[] = $name.' = '.($component == '' ? 'empty' : $component);
$rowcount++;
}
}
//creating row
$count = 0;
foreach ($strings as $string) {
if ($count == 0) {
$frow[] = new TableCell($key, ['rowspan' => $rowcount]);
$frow[] = $string;
} else {
$row[] = $string;
}
$count++;
}
$rows = [$frow,$row];
var_dump($rows);
$table->addRows($rows);
unset($frow,$row,$strings);
}
}
$table->setStyle('borderless');
$table->render();
The var_dump at this point creates this result
array(2) {
[0]=>
array(2) {
[0]=>
object(Symfony\Component\Console\Helper\TableCell)#63 (2) {
["value":"Symfony\Component\Console\Helper\TableCell":private]=>
string(5) "forms"
["options":"Symfony\Component\Console\Helper\TableCell":private]=>
array(2) {
["rowspan"]=>
int(4)
["colspan"]=>
int(1)
}
}
[1]=>
string(12) "name = forms"
}
[1]=>
array(3) {
[0]=>
string(18) "path = admin/forms"
[1]=>
string(14) "scope = system"
[2]=>
string(16) "attachto = empty"
}
}
The CLI should appear like this
============= ===================
Elements Properties
============= ===================
forms name = forms
path = admin/forms
scope = system
attachto = empty
I don't know if this is too much but the problem is the alignment of the second column is completely disjointed.The scope=system section moves to a 3rd column.

find / select specified ID in array php

i have array with database, and have to select only this items what have "tid" = 1
array(3) {
[1]=>
array(4) {
["tid"]=> "1"
["title"]=> "Google"
["url"]=> "http://google.com/"
["description"]=> "A very efficient search engine."
}
[2]=>
array(4) {
["tid"]=> "2"
["title"]=> "Facebook"
["url"]=> "http://facebook.com/"
["description"]=> "Trade securities, currently supports nearly 1000 stocks and ETFs"
}
[3]=>
array(4) {
["tid"]=> "1"
["title"]=> "Yandex"
["url"]=> "http://yandex.ru/"
["description"]=> "Another efficient search engine popular in Russia"
}
}
how can i select only this items from array what have "tid" = 1?
<?php
$final_arr = array();
foreach($tid_arrs as $tid_arr){
if($tid_arr['tid'] == 1){
$final_arr[] = $tid_arr;
}
}
print_r($final_arr);
?>
$filteredArray = array();
for($i = 0, $end = count($array);$i < $end;i++)
{
if($array[$i]["tid"] === "1")
{
$filderedArray[] = $array[$i];
}
}
That way $filteredArray will contain solely the items with tid 1;
Try array_filter function: http://php.net/manual/en/function.array-filter.php this should help.
print_r(array_filter($array, "filter_function"));
function filter_function($element){
return (int)$element['tid'] === 1;
}
let's say you starting array is $arr.
$result = array();
foreach ($arr as $arrItem) {
if ((array_key_exists('tid', $arrItem)) && ($arrItem['tid'] == "1")){
$result[] = $arrItem;
}
}
$result should be what you are excepted.

Categories