Nested array to single array keeping the parents - php

The problem is to change a tree structure to a simple array structure, in which each child has the parents who belongs to, the example is a directories and files structure, but I'm looking for a generic solution.
If the writing is bad, feel free to improve it.
Any help is welcome.
Example.
$array_1=array(
'f1' =>
array(
'f2' =>array('file1.php','file2.php'),
'f3' =>array('file3.php','file4.php'),
'f4' =>
array(
'fol5'=>
array('fileAA.php','fileBB.php')
,
'fileDD.php'
),
),
'f2' =>
array(
'f2' =>array('file1.php','file2.php'),
'f3' =>array('file3.php'),
)
);
The result should be like this:
/*
0 => '/f1/f2/file1.php',
1 => '/f1/f2/file2.php',
2 => '/f1/f3/file3.php',
3 => '/f1/f3/file4.php',
4 => '/f1/f4/fol5/fileAA.php',
5 => '/f1/f4/fol5/fileBB.php',
6 => '/f1/f4/fileDD.php',
7 => '/f2/f2/file1.php',
8 => '/f2/f2/file2.php',
9 => '/f2/f3/file3.php',
*/

here is simple recursive function:
function tree2array($input, &$output, $prefix = '')
{
foreach ($input as $i => $v)
if (is_array($v))
tree2array($v, $output, $prefix.'/'.$i);
else
$output[] = $prefix.'/'.$v;
}
usage:
tree2array($array_1, $array2);
output:
print_r($array2);
Array (
[0] => /f1/f2/file1.php
[1] => /f1/f2/file2.php
[2] => /f1/f3/file3.php
[3] => /f1/f3/file4.php
[4] => /f1/f4/fol5/fileAA.php
[5] => /f1/f4/fol5/fileBB.php
[6] => /f1/f4/fileDD.php
[7] => /f2/f2/file1.php
[8] => /f2/f2/file2.php
[9] => /f2/f3/file3.php )

I made an alternative solution using SPL
$arrayiter = new RecursiveArrayIterator($array_1);
$iteriter = new RecursiveIteratorIterator($arrayiter,RecursiveIteratorIterator::CHILD_FIRST);
foreach ($iteriter as $key => $value) {
$this_depth = $iteriter->getDepth();
if(!is_array($value)){
$array_2[] = '/'.$value;
$level[]=$this_depth;
}
foreach($array_2 as $key2 => $value2){
if($this_depth < $level[$key2]){
$level[$key2] = $this_depth;
$array_2[$key2] = '/'.$key.$value2;
}
}
}
echo'<pre>';
print_r($array_2);
echo'</pre>';

Related

How to remove the duplicate data into array [duplicate]

This question already has answers here:
Filter/Remove rows where column value is found more than once in a multidimensional array
(4 answers)
Closed 9 months ago.
Need help for the code.
Here is my list of array which i want to remove the two (2) Wi-fi.
Array
(
[20-10] => Array
(
[facilityCode] => 20
[facilityGroupCode] => 10
[order] => 1
[number] => 1968
[voucher] =>
[description] => Year of construction
)
[550-70] => Array
(
[facilityCode] => 550
[facilityGroupCode] => 70
[order] => 1
[indFee] =>
[indYesOrNo] => 1
[voucher] =>
[description] => Wi-fi
)
[20-60] => Array
(
[facilityCode] => 20
[facilityGroupCode] => 60
[order] => 1
[indLogic] => 1
[voucher] =>
[description] => Shower
)
[261-60] => Array
(
[facilityCode] => 261
[facilityGroupCode] => 60
[order] => 1
[indFee] =>
[indYesOrNo] => 1
[voucher] =>
[description] => Wi-fi
)
)
I do also tried the array_unique();
here is the result:
Array
(
[0] => Year of construction
[1] => Shower
[2] => Wi-fi
)
But i want to keep the facilityCode,facilityGroupCode,order,number etc.
Thanks for any help.
One liner is all can do your requirement,
$result = array_reverse(array_values(array_column(array_reverse($arr), null, 'description')));
Source link for your requirement.
//populate data
$mainArr = array();
$first = array(
"facilityCode" => 20,
"facilityGroupCode" => 10,
"order" => 1,
"number" => 1968,
"voucher" => "",
"description" => "Year of construction",
);
$second = array(
"facilityCode" => 550,
"facilityGroupCode" => 70,
"order" => 1,
"indFee" => "",
"indYesOrNo" => 1,
"voucher" => "",
"description" => "Wi-fi"
);
$mainArr["20-10"] = $first;
$mainArr["550-70"] = $second;
$mainArr["261-60"] = $second;
//get duplicates
$counter = 0;
$duplicates = array();
foreach ($mainArr as $key=>$val) {
$counter++;
if (in_array($key, $duplicates)) continue;
$i = 0;
foreach ($mainArr as $key1=>$val1) {
if ($i < $counter) {
$i++;
continue;
}
if ($val["description"] == $val1["description"]) {
array_push($duplicates, $key1);
}
}
}
//remove duplicates
foreach($duplicates as $key) {
unset($mainArr[$key]);
}
$itemRows = array(); // Your main array
$descriptionValues = array();
foreach ($itemRows as $itemKey => $itemRow) {
foreach ($itemRow as $key => $value) {
if ($key == 'description') {
if (in_array($value, $descriptionValues)) {
unset($itemRows[$itemKey]);
continue 2;
}
$descriptionValues[] = $value;
}
}
}

Only permit one instance of a row with a particular column value in a multidimensional array

In my input array, I have multiple rows with a userTag of All, but I only want a maximum of one. Other rows my have duplicated userTag values (such as Seeker), but extra All rows must be removed.
$input = [
0 => ['userTag' => 'All', 'fbId' => 10210118553469338, 'price' => 70],
1 => ['userTag' => 'All', 'fbId' => 10210118553469338, 'price' => 14],
2 => ['userTag' => 'All', 'fbId' => 10210118553469338, 'price' => null],
3 => ['userTag' => 'Seeker', 'fbId' => 10207897577195936, 'price' => 65],
6 => ['userTag' => 'Seeker', 'fbId' => 709288842611719, 'price' => 75],
17 => ['userTag' => 'Trader', 'fbId' => 2145752308783752, 'price' => null]
];
My current code:
$dat = array();
$dat2 = array();
foreach ($input as $key => $value)
{
$i = 0;
$j = 0;
if (count($dat) == 0) {
$dat = $input[$key];
$i++;
} else {
if ($input[$key]['userTag'] == "All") {
if ($this->check($input[$key]['fbId'], $dat) == false) {
$dat[$i] = $input[$key];
$i++;
}
} else {
$dat2[$j] = $input[$key];
$j++;
}
}
}
$data = array_merge($dat, $dat2);
return $data;
The check() function:
public function check($val, $array) {
foreach ($array as $vl) {
if ($val == $array[$vl]['fbId']) {
return true;
break;
}
}
return false;
}
You can try something simple like this:
$data = [];
foreach($input as $key => $value)
{
$counter = 0;
if($value['userTag'] =="All"){
if($counter == 0 ) {//test if is the first userTag == All
$counter = 1;//increment the counter so the if doesn't trigger and the value isn't appended
$data[] = $value;//add it to the array
}
} else {
$data[] = $value;//keep the rest of the values
}
}
return $data;
You can use the below code, This will remove all duplicate values from your array.
$arr = array_map("unserialize", array_unique(array_map("serialize", $arr)));
UPDATED ANSWER
The updated answer below is the accurate solution asked in the question which helps with All rows data too.
$temp = array();
foreach($arr as $key => $val) {
if ($val['userTag'] == "All" && empty($temp)) {
$temp[$key] = $arr[$key];
unset($arr[$key]);
}
else if ($val['userTag'] == "All") {
unset($arr[$key]);
}
}
$arr = array_merge($arr, $temp);
Check this code. Perfectly working.
$n_array = array();$i=0;
foreach($array as $row){
if($row['userTag']=="All"){
if($i==0){
$n_array[]=$row;
$i=1;
}
}
else $n_array[]=$row;
}
echo "<pre>";print_r($n_array);
Result
Array
(
[0] => Array
(
[userTag] => All
[fbId] => 10210118553469338
[fName] => Danish
[lName] => Aftab
[imageUrl] => https://scontent.xx.fbcdn.net/v/t1.0-1/p50x50/22491765_10210410024475931_8589925114603818114_n.jpg?oh=7fa6266e7948ef2d218076857972f7e0
[subsType] => gold
[user_visible] => 0
[distance] => 0.01
[advising] => 0
[avgRate] => 4
[totalReview] => 2
[us_seeker_type] => new
[price] => 70
)
[1] => Array
(
[userTag] => Seeker
[fbId] => 10207897577195936
[fName] => Saq
[lName] => Khan
[imageUrl] => https://scontent.xx.fbcdn.net/v/t1.0-1/p50x50/21151741_10207631130774942_8962953748374982841_n.jpg?oh=f5e5b9dff52b1ba90ca47ade3d703b01
[subsType] => gold
[user_visible] => 0
[background] =>
[topic] =>
[distance] => 0.01
[advising] => 0
[avgRate] => 0
[totalReview] => 0
[us_seeker_type] => new
[price] => 65
)
[2] => Array
(
[userTag] => Seeker
[fbId] => 709288842611719
[fName] => Muhammad
[lName] => Hasan
[imageUrl] => https://scontent.xx.fbcdn.net/v/t1.0-1/p50x50/20264704_681395725401031_2098768310549259034_n.jpg?oh=36db5b6ed60214088750794d4e3aa3e6
[subsType] => gold
[user_visible] => 0
[distance] => 0.02
[advising] => 0
[avgRate] => 0
[totalReview] => 0
[us_seeker_type] => new
[price] => 75
)
[3] => Array
(
[userTag] => Trader
[fbId] => 2145752308783752
[fName] => Jawaid
[lName] => Ahmed
[imageUrl] => https://scontent.xx.fbcdn.net/v/t1.0-1/p50x50/20992899_2068273703198280_4249128502952085310_n.jpg?oh=6df0be6ced405dd66ee50de238156183
[subsType] => basic
[user_visible] => 0
[advising] => 0
[distance] => 0
[avgRate] => 0
[totalReview] => 0
[utr_trader_type] => new
[price] =>
)
)
To keep only the first occurrence of the All row, build an array where All is used as a first level key in the result array. If the row isn't an All row, just keep using its original numeric key. Using the ??= "null coalescing assignment operator", you ensure that only the first All value is stored and all subsequently encountered All rows are ignored.
Code: (Demo)
$result = [];
foreach ($array as $key => $row) {
$result[$row['userTag'] === 'All' ? 'All' : $key] ??= $row;
}
var_export($result);
If you don't want to have the All key for later processing reasons, you can replace it by un-setting then re-pushing it into the array (after finishing the loop).
$result[] = $result['All']; // or unshift($result, $result['All']) to the start of the array
unset($result['All']);

How to merge an array with child elements

I have an array with same customerid. I want to merge all same customerid arrays in to one with few amends to the array.
Array
(
[0] => Array
(
[customerid] => 13
[customer_fullname] => Chris
[profession_id] => 8
[profession_name] => Producer
)
[1] => Array
(
[customerid] => 1
[customer_fullname] => John
[profession_id] => 8
[profession_name] => Producer
)
[2] => Array
(
[customerid] => 13
[customer_fullname] => Chris
[profession_id] => 7
[profession_name] => Camera
)
)
So now I want a new array to be created like this:
Array(
[customerid] => 13
[customer_fullname] => Chris
[new_array] => array(
[0]=>[profession_id] => 8, [profession_name] => Producer,
[1]=>[profession_id] => 7, [profession_name] => Camera
)
)
Spent some time on it but wasn't able to get it right
There are better approaches if you're merging lots of records, but if you want a way to just merge two records as stated, I'd just do this:
$array1 = array(
'customerid' => 13
'customer_fullname' => 'John',
'profession_id' => 8,
'profession_name' => 'Producer'
);
$array2 = array(
'customerid' => 13
'customer_fullname' => 'John',
'profession_id' => 7,
'profession_name' => 'Director'
);
function merge_customers($customerA, $customerB)
{
$newCustomer = array();
if ($customerA['customerid'] == $customerB['customerid'])
{
$newCustomer['customerid'] = $customerA['customerid'];
$newCustomer['customer_fullname'] = $customerA['customer_fullname'];
$newCustomer['new_array'] = array(
array(
'profession_id' => $customerA['profession_id'],
'profession_name' => $customerA['profession_name']
),
array(
'profession_id' => $customerB['profession_id'],
'profession_name' => $customerB['profession_name']
)
);
return $newCustomer;
}
/* We can't merge these if they're different customers. */
return NULL;
}
The extended solution which is also well-suited for finding and "merging" multiple groups of entries which has same customerid. Used functions: array_filter, array_count_values, array_keys, array_walk, array_chunk and array_values:
// supposing $arr is your initial array
// finds which 'customerid' has multiple entries
$dupIds = array_filter(array_count_values(array_column($arr, "customerid")), function($v) {
return $v > 1;
});
$dupIds = array_keys($dupIds);
$result = [];
array_walk($arr, function($v) use(&$result, $dupIds) {
if (in_array($v['customerid'], $dupIds)) {
$parts = array_chunk($v, 2, true);
if (!isset($result[$v['customerid']])) {
$result[$v['customerid']] = $parts[0] + ['new_array' => [$parts[1]]];
} else {
$result[$v['customerid']]['new_array'][] = $parts[1];
}
}
});
print_r(array_values($result));
The output:
Array
(
[0] => Array
(
[customerid] => 13
[customer_fullname] => Chris
[new_array] => Array
(
[0] => Array
(
[profession_id] => 8
[profession_name] => Producer
)
[1] => Array
(
[profession_id] => 7
[profession_name] => Camera
)
)
)
)
Quick hack, maybe there is a nicer solution.
Note: The second "for each" loop is only needed if there is the possibility that the arrays don't have the same fields.
function merge($array1, $array2){
$result = array();
foreach($array1 as $key => $value){
if(isset($array2[$key]) && $array2[$key]!=$array1[$key]){
$result[$key][]=$value;
$result[$key][]=$array2[$key];
}else{
$result[$key]=$value;
}
}
foreach($array2 as $key => $value){
if(!isset($result[$key])){
$result[$key] = $value;
}
}
return $result;
}
print_r(merge($array1, $array2));

using array merge into a foreach loop

I need to merge a new array of alternative information into the loop if they have the alternative information in their profile.
Here's my loop:
foreach ($doctor->getVars() as $k => $v)
{
$data['doctor_'. $k] = $v;
}
foreach ($patient->get_data() as $k=>$v)
{
if (is_string($v) || is_numeric($v))
$data["patient_" . $k] = strtoupper($v);
}
Here's the $data var_dump:
Array
(
[employee] => person
[date] => 05/08/2013
[datetime] => 05/08/2013 9:41:15 AM
[department] => stuff
[employee_ext] => 7457
[employee_email] =>
[barcode] => *NZS01*
[doctor_df_code] => 09HQ
[doctor_npi] => 1111111111
[doctor_dea] => B4574
[doctor_upin] =>
[doctor_license] =>
[doctor_phone] => (111)111-1111
[doctor_fax] => (000)000-0000
[doctor_fname] => UNDEFINED
[doctor_lname] => UNDEFINED
[doctor_title] =>
[doctor_intake_rx_caller_id] =>
[doctor_costco_rx_caller_id] =>
[doctor_reorder_rx_caller_id] =>
[doctor_address1] => 24 CABELL st
[doctor_address2] => SUITE 10
[doctor_city] => places
[doctor_state] => CA
[doctor_zip] => 91111
[doctor_active_events] =>
[doctor_dont_call] => 0
[doctor_dont_fax] => 1
)
I need to merge the below array into the above array.
Here's the print var for the function addr($dfcode):
Array
(
[0] => Array
(
[CODE_] => 09HQ
[doctor_address1] => alternate addy
[doctor_address2] => 45854
[doctor_city] => different city
[doctor_state] => CA
[doctor_zip] => 963545
[doctor_phone] => (619)111-2548
[doctor_fax] => (157)123-4569
)
)
I'm new to array merge and I'm assuming right after the $data['doctor_'. $k] = $v i could list out the new function and the fields i want to merge in particular?
syntax is what i'm not sure on:
$data['doctor_'. $k] . array_merge(addr($dfcode))['doctor_address1'] = $v;
Any help would be greatly appreciated, thank you.
The general formula for merging two arrays is as follows (merging $array_m into $array_o):
foreach($array_m as $key=>$value){
$array_o[$key] = $value;
}
$array_o would now contain all of the elements of $array_m
EDIT: I just noticed in your post that you seem to want to use the array_merge function. You could also do the following:
$array_o = array_merge($array_o, array_m);

PHP arrays. There must be a simpler method to do this

I have this array in php returned from db
Array
(
[inv_templates] => Array
(
[0] => Array
(
[inven_subgroup_template_id] => 1
[inven_group] => Wires
[inven_subgroup] => CopperWires
[inven_template_id] => 1
[inven_template_name] => CopperWires6G
[constrained] => 0
[value_constraints] =>
[accept_range] => 2 - 16
[information] => Measured Manual
)
[1] => Array
(
[inven_subgroup_template_id] => 1
[inven_group] => Wires
[inven_subgroup] => CopperWires
[inven_template_id] => 2
[inven_template_name] => CopperWires2G
[constrained] => 0
[value_constraints] =>
[accept_range] => 1 - 7
[information] => Measured by Automated Calipers
)
)
)
I need to output this kind of multidimensional stuff
Array
(
[Wires] => Array
(
[inv_group_name] => Wires
[inv_subgroups] => Array
(
[CopperWires] => Array
(
[inv_subgroup_id] => 1
[inv_subgroup_name] => CopperWires
[inv_templates] => Array
(
[CopperWires6G] => Array
(
[inv_name] => CopperWires6G
[inv_id] => 1
)
[CopperWires2G] => Array
(
[inv_name] => CopperWires2G
[inv_id] => 2
)
)
)
)
)
)
I currently do this stuff
foreach ($data['inv_templates'] as $key => $value) {
$processeddata[$value['inven_group']]['inv_group_name'] = $value['inven_group'];
$processeddata[$value['inven_group']]['inv_subgroups'][$value['inven_subgroup']]['inv_subgroup_id'] = $value['inven_subgroup_template_id'];
$processeddata[$value['inven_group']]['inv_subgroups'][$value['inven_subgroup']]['inv_subgroup_name'] = $value['inven_subgroup'];
$processeddata[$value['inven_group']]['inv_subgroups'][$value['inven_subgroup']]['inv_templates'][$value['inven_template_name']]['inv_name'] = $value['inven_template_name'];
$processeddata[$value['inven_group']]['inv_subgroups'][$value['inven_subgroup']]['inv_templates'][$value['inven_template_name']]['inv_id'] = $value['inven_template_id'];
}
return $processeddata;
EDIT : A var_export
array (
'inv_templates' =>
array (
0 =>
array (
'inven_subgroup_template_id' => '1',
'inven_group' => 'Wires',
'inven_subgroup' => 'CopperWires',
'inven_template_id' => '1',
'inven_template_name' => 'CopperWires6G',
'constrained' => '0',
'value_constraints' => '',
'accept_range' => '2 - 16',
'information' => 'Measured Manual',
),
1 =>
array (
'inven_subgroup_template_id' => '1',
'inven_group' => 'Wires',
'inven_subgroup' => 'CopperWires',
'inven_template_id' => '2',
'inven_template_name' => 'CopperWires6G',
'constrained' => '0',
'value_constraints' => '',
'accept_range' => '1 - 7',
'information' => 'Measured by Automated Calipers',
),
),
)
The foreach is almost unreadable. There must be a simpler way
$processeddata = array();
foreach($data['inv_templates'] as $key => $value) {
$group = $value['inven_group'];
$processeddata[$group]['inv_group_name'] = $group;
$subgroup = &$processeddata[$group]['inv_subgroups'][$value['inven_subgroup']];
$subgroup['inv_subgroup_id'] = $value['inven_subgroup_template_id'];
$subgroup['inv_subgroup_name'] = $value['inven_subgroup'];
$template = $value['inven_template_name'];
$subgroup['inv_templates'][$template]['inv_name'] = $template;
$subgroup['inv_templates'][$template]['inv_id'] = $value['inven_template_id'];
}
return $processeddata;
Untested code. This structures the array in a multidimensional way, and then uses array_merge_recursive to merge them with the already processed data.
if (!isset($processeddata[$value['inven_group']]))
$processeddata[$value['inven_group']] = array();
$processeddata[$value['inven_group']] = array_merge_recursive(
$processeddata[$value['inven_group']],
array(
'inv_group_name' => $value['inven_group'],
'inv_subgroups' => array(
$value['inven_subgroup'] => array(
'inv_subgroup_id' => $value['inven_subgroup_template_id'],
'inv_subgroup_name' => $value['inven_subgroup'],
'inv_templates' => array(
$value['inven_template_name'] => array(
'inv_name' => $value['inven_template_name'],
'inv_id' => $value['inven_template_id'],
),
),
),
),
)
);
I find this format usually works for me. You could do it more efficient, I've just never cared :D
I started traversing at $yourArray['inv_templates'] though.
function groupToStructure(array $rows, array $keys) {
$tree = array();
$keys = array_reverse($keys);
foreach ($rows as $row) {
$subTree = array($row);
foreach ($keys as $key) {
$subTree = array($row[$key] => $subTree);
}
$tree = array_merge_recursive($tree, $subTree);
}
return $tree;
}
print_r(groupToStructure($rows, array('inven_group', 'inven_subgroup', 'inven_template_name')));

Categories