PHP array merge / map of two arrays - php

I have two arrays, one that contains all options, and a second one that contains the default values.
The options arrays looks like this:
$options = array(
"SeriesA" => array(
"A1" => array(
"text" => "A1",
"value" => "A-001"
),
"A2" => array(
"text" => "A2",
"value" => "A-002"
)
),
"SeriesB" => array(
"B1" => array(
"text" => "B2",
"value" => "B-001"
),
"B2" => array(
"text" => "B2",
"value" => "B-002"
)
),
);
And I have another array that contains default value, and it looks like this
$defaults= array(
"SeriesA" => "A-002",
"SeriesB" => "B-001",
);
What I would like to end up with is one array that contains all info,
is there a way that I can map both arrays and get one array that will look like this:
$options = array(
"SeriesA" => array(
"A1" => array(
"text" => "A1",
"value" => "A-001",
"default" => false
),
"A2" => array(
"text" => "A2",
"value" => "A-002",
"default" => true
)
),
"SeriesB" => array(
"B1" => array(
"text" => "B2",
"value" => "B-001",
"default" => true
),
"B2" => array(
"text" => "B2",
"value" => "B-002",
"default" => false
)
),
);

Here is two ways to do it:
Make a function, which accepts two args and check value in a loop with defaults, add defaults, and returns new array, or edit array, passing it by reference:
function awesomeName(&$options, $defaults) {
foreach ($options as $k => &$values) {
foreach ($values as &$AsAndBs) {
$AsAndBs['default'] = $AsAndBs['value'] == $defaults[$k];
}
}
}
Using array_walk() function with anonymous function:
array_walk($options, function (&$v, $k) use ($defaults) {
$series = $k;
foreach ($v as &$series_contents) {
$series_contents['default'] = $series_contents['value'] == $defaults[$series];
}
});

Related

Recursively getting a list of parents for each node in a nested PHP array

In PHP I have a set of nested arrays of data. I want to flatten these, so that for every node and leaf I get a list of its parents.
Here's an example of the original array - note, each part could be of an unknown depth and length:
$data = array(
"name" => "Thing",
"children" => array(
array(
"name" => "Place",
"rdfs:subClassOf" => "schema:Thing",
"children" => array(
array(
"name" => "Accomodation",
"rdfs:subClassOf" => "schema:Place",
"children" => array(
array(
"name" => "Apartment",
"rdfs:subClassOf" => "schema:Accomodation",
),
array(
"name" => "Hotel",
"rdfs:subClassOf" => "schema:Accomodation",
),
array(
"name" => "House",
"rdfs:subClassOf" => "schema:Accomodation",
)
)
)
)
),
array(
"name" => "CreativeWork",
"rdfs:subClassOf" => "schema:Thing",
"children" => array(
array(
"name" => "Article",
"rdfs:subClassOf" => "schema:CreativeWork",
"children" => array(
array(
"name" => "NewsArticle",
"rdfs:subClassOf" => "schema:Article",
),
array(
"name" => "OpinionArticle",
"rdfs:subClassOf" => "schema:Article",
),
)
)
)
)
)
);
(The data I'm actually parsing is this Schema.org JSON file - the above is a minimal example of it.)
And here's what I'd like to end up with:
$results = array(
"Place" => array("Thing"),
"Accomodation" => array("Thing", "Place"),
"Apartment" => array("Thing", "Place", "Accomodation"),
"Hotel" => array("Thing", "Place", "Accomodation"),
"House" => array("Thing", "Place", "Accomodation"),
"CreativeWork" => array("Thing"),
"Article" => array("Thing", "CreativeWork"),
"NewsArticle" => array("Thing", "CreativeWork", "Article"),
"OpinionArticle" => array("Thing", "CreativeWork", "Article"),
);
I'm assuming I need to recursively call a function to build the array but so far I'm not having much luck. In case this makes it harder, this is happening in a static method.
Something quick to get you started:
class Parser {
public static function parse($input,$prefix = []) {
$return = $prefix ? [$input['name']=>$prefix] : [];
if (isset($input['children'])) {
$prefix[] = $input['name'];
foreach ($input['children'] as $child) {
$return += self::parse($child,$prefix);
}
}
return $return;
}
}
var_dump(Parser::parse($data));
You probably need to add a few checks and comments to make it more readable.

Construct an associative array from 2 other arrays, and linked by a common key

Problem:
I would like to combine 2 associative arrays to make one. To link these arrays, the ID key is present in both.
Input:
To retrieve my contacts with api call, I have to do 2 requests :
First to retrieve contacts with Id, and email adresse
Second to get some informations like name, city etc.
The first one return an array like this :
$contactArray = array(
array(
"CreatedAt" => "2019-04-12T11:53:26Z",
"DeliveredCount" => 0,
"Email" => "terry#example.org",
"ExclusionFromCampaignsUpdatedAt" => "2019-04-28T09:21:35Z",
"ID" => 1864410583,
"IsExcludedFromCampaigns" => false,
"IsOptInPending" => false,
"IsSpamComplaining" => false,
"LastActivityAt" => "2019-04-28T09:21:35Z",
"LastUpdateAt" => "2019-04-28T09:21:35Z",
"Name" => "",
"UnsubscribedAt" => "",
"UnsubscribedBy" => ""
),
array(
"CreatedAt" => "2019-04-12T12:39:30Z",
"DeliveredCount" => 0,
"Email" => "duane#example.org",
"ExclusionFromCampaignsUpdatedAt" => "",
"ID" => 1864410588,
"IsExcludedFromCampaigns" => false,
"IsOptInPending" => false,
"IsSpamComplaining" => false,
"LastActivityAt" => "2019-04-12T12:39:30Z",
"LastUpdateAt" => "2019-04-12T12:39:30Z",
"Name" => "",
"UnsubscribedAt" => "",
"UnsubscribedBy" => ""
)
);
The second call, return an array like
$contactDataArray =
array(
array(
"ContactID" => 1864410583,
"Data" => array(
array(
"Name" => "firstname",
"Value" => "Mark"
),
array(
"Name" => "city",
"Value" => "Miami"
),
array(
"Name" => "name",
"Value" => "Terry"
),
array(
"Name" => "phone",
"Value" => "555-5555"
)
),
"ID" => 1864410583
),
array(
"ContactID" => 1864410588,
"Data" => array(
array(
"Name" => "firstname",
"Value" => "Jane"
),
array(
"Name" => "city",
"Value" => "New York"
),
array(
"Name" => "name",
"Value" => "Duane"
),
array(
"Name" => "phone",
"Value" => "555-5555"
)
),
"ID" => 1864410588
)
);
In $contactArray, the ID key matches with ContactID key and ID key in $contactDataArray
Attempt:
I want an array formatted like this :
$output = array(
array(
"Email" => "terry#example.org",
"ID" => 1864410583,
"firstname" => "Mark",
"city" => "Miami",
"name" => "Terry",
"phone" => "555-5555"
),
array(
"Email" => "duane#example.org",
"ID" => 1864410588,
"firstname" => "Jane",
"city" => "New York",
"name" => "Duane",
"phone" => "555-5555"
)
);
I'm trying to achieve this with array_walk, but no succeed.
You can do this with foreach,
$result = [];
foreach ($contactDataArray as $key => $value) {
$ids = array_column($contactArray, "ID"); // fetching all values from contactArray
if (!empty(array_intersect([$value['ContactID'], $value['ID']], $ids))) { // checking if both satisfy the condition
$result[$key] = array_column($value['Data'], 'Value', 'Name'); // combining name and value
// searchng for key with matched ContactID
$result[$key]['Email'] = $contactArray[array_search($value["ContactID"], $ids)]['Email'];
$result[$key]['ID'] = $value["ContactID"];
}
}
Demo.
Can you please try with this?
$output = [];
for($i = 0; $i < count($contactDataArray); $i++) {
$arrIDandEmail = [
'Email' => isset($contactArray[$i]['Email']) ? $contactArray[$i]['Email'] : '',
'ID' => isset($contactDataArray[$i]['ID']) ? $contactDataArray[$i]['ID'] : ''
];
$arrData = array_column($contactDataArray[$i]["Data"], "Value", "Name");
$newArray = array_merge($arrIDandEmail, $arrData);
$output[] = $newArray;
}
For PHP >= 7.1 you can use array destructuring using list()
<?php
$output = [];
foreach ($contactDataArray as [
'ID' => $id,
'Data' => [
['Name' => $firstnameKey, 'Value' => $firstnameValue],
['Name' => $cityKey, 'Value' => $cityValue],
['Name' => $nameKey, 'Value' => $nameValue],
['Name' => $phoneKey, 'Value' => $phoneValue]
]
]) {
$output[] = [
"Email" => $contactArray[array_search($id, array_column($contactArray, 'ID'))]['Email'],
"ID" => $id,
$firstnameKey => $firstnameValue,
$cityKey => $cityValue,
$nameKey => $nameValue,
$phoneKey => $phoneValue
];
}
var_dump($output);
Demo
You can use array_walk,array_combine,array_column for the desired array as a result
$res = [];
array_walk($contactArray, function($v, $k) use ($contactDataArray,&$res)
{
$res[] = array_merge(['Email'=>$v['Email'],'ID'=>$v['ID']],
array_combine(
array_column($contactDataArray[$k]['Data'],'Name'),
array_column($contactDataArray[$k]['Data'],'Value')
)
);
});
echo '<pre>';
print_r($res);
DEMO

How to consolidate duplicate elements of this array in PHP?

I have an array like this:
$array = array(
0 => array("ordernumber" => "1", "name" => "John", "product" => "laptop", "component" => "memory"),
1 => array("ordernumber" => "1", "name" => "John", "product" => "laptop", "component" => "cpu"),
2 => array("ordernumber" => "1", "name" => "John", "product" => "desktop", "component" => "cpu"),
3 => array("ordernumber" => "2", "name" => "Pete", "product" => "monitor", "component" => "")
);
It contains data from different orders, but as you can see an order can contain multiple purchased products, and each product can contain different 'components'. There's alot of duplicate data in this array, so I would like to turn it into this:
$array = array(
0 => array(
"order" => array(
"ordernumber" => "1", "name" => "John"
),
"products" => array(
0 => array(
"name" => "laptop",
"components" => array("memory", "cpu")
),
1 => array(
"name" => "desktop",
"components" => array("cpu")
)
)
),
1 => array(
"order" => array(
"ordernumber" => "2", "name" => "Pete"
),
"products" => array(
0 => array(
"name" => "monitor",
"components" => array()
)
)
)
);
What would be a good way to do this?
Please use below code to make the solution what you want
<?php
$array = array(
0 => array("ordernumber" => "1", "name" => "John", "product" => "laptop", "component" => "memory"),
1 => array("ordernumber" => "1", "name" => "John", "product" => "laptop", "component" => "cpu"),
2 => array("ordernumber" => "1", "name" => "John", "product" => "desktop", "component" => "cpu"),
3 => array("ordernumber" => "2", "name" => "Pete", "product" => "monitor", "component" => "")
);
$final_array = [];
foreach($array as $k=>$v){
$final_array[$v['ordernumber']]['order']['ordernumber'] = $v['ordernumber'];
$final_array[$v['ordernumber']]['order']['name'] = $v['name'];
$final_array[$v['ordernumber']]['products'][$v['product']]['name'] = $v['product'];
$final_array[$v['ordernumber']]['products'][$v['product']]['components'][] = $v['component'];
}
// You can skip this foreach if there will not metter of KEY of an array in your code!
$final_array = array_values($final_array);
foreach($final_array as $k=>$v){
$final_array[$k]['products'] = array_values($final_array[$k]['products']);
}
echo "<pre>";
print_r($final_array);
?>
its should work!!

Nested array. Third level is disappearing

I have that array :
$a = array(
"7" => array(
"id" => 7,
"parent" => 6
),
"6" => array(
"id" => 6,
"parent" => 5
),
"5" => array(
"id" => 5,
"parent" => 4
),
"4" => array(
"id" => 4,
"parent" => 0
),
"3" => array(
"id" => 7,
"parent" => 2
),
"2" => array(
"id" => 7,
"parent" => 1
),
"1" => array(
"id" => 7,
"parent" => 0
)
);
the result that I want is that :
$a = array(
"4" => array(
"id" => 4,
"parent" => 0,
array(
"5" => array(
"id" => 5,
"parent" => 4,
array(
"6" => array(
"id" => 6,
"parent" => 5,
array(
"7" => array(
"id" => 7,
"parent" => 6
)
)
)
)
)
)
),
"2" => array(
"id" => 7,
"parent" => 1,
array(
"3" => array(
"id" => 7,
"parent" => 2
)
)
),
"1" => array(
"id" => 7,
"parent" => 0
)
);
the code that I use is this :
foreach($a as $v)
{
if(isset($a[$v['PARENT']]))
{
$a[$v['PARENT']][$v['ID']] = $v;
unset($a[$v['ID']]);
}
}
and the problem that I have is that I get that result :
$a = array(
"4" => array(
"id" => 4,
"parent" => 0,
array(
"5" => array(
"id" => 5,
"parent" => 4
)
)
),
"2" => array(
"id" => 7,
"parent" => 1,
array(
"3" => array(
"id" => 7,
"parent" => 2
)
)
),
"1" => array(
"id" => 7,
"parent" => 0
)
);
instead of the need it result.
To solve your problem you need to properly understand how variable referencing/aliasing in PHP works.
Look at the following example code, which does not look much different to yours but makes use of references in order to access any parent even it has already "moved":
# transform $flat into a tree:
foreach($flat as $id => &$value)
{
# check if there is a parent
if ($parentId = $value['parent'])
{
$flat[$parentId][0][$id] =& $value; # add child to parent
unset($flat[$id]); # remove reference from topmost level
}
}
unset($value); # remove iterator reference
print_r($flat); # your tree
$flat now contains all values from $flat - but reordered. Demo.
Are you sure that output array is correct? Surely the key 2 should be a child of 1 (since 2 has 'parent'=>1)? If this is not the case, I don't understand what are actually trying to do and how the keys all relate to each other.
If 2 should be a child of 1, this works:
$keep = array();
foreach ($a as $k => &$v) {
// Loop the array first time and create references to
// structure the array how you want it
if ($v['parent']) {
$a[$v['parent']][0] = array($k => &$v);
} else $keep[] = $k;
}
foreach ($a as $k => $v) {
// Loop it again to get rid of non-root nodes from the root
if (!in_array($k,$keep)) {
unset($a[$k]);
}
}
print_r($a);

Adding a new array to an array if it doesn't already exist

I currently have this array in layout.php
<?php
$arrLayout = array(
"section1" => array(
"wControl" => array(
"title" => "Control",
"display" => ""
),
"wRecentTV" => array(
"title" => "Recent TV",
"display" => ""
)
),
"section2" => array(
"wXBMCLibrary" => array(
"title" => "XBMC Library",
"display" => ""
)
),
"section3" => array(
"wSearch" => array(
"title" => "Search",
"display" => ""
),
"wRSS" => array(
"title" => "RSS Feed",
"display" => ""
)
),
);
?>
What I want to so is say. If ( $wControl == "true" ) and 'wControl' is not in any section then write
,
"wControl" => array(
"title" => "Control",
"display" => ""
)
to the end of section x between the ) and ), and rewrite the file.
Basically wControl may or may not exist in any one of the sections. So if it doesn't exist it must be added to the array and layout.php must be rewritten to show it. Hope that all makes sense.
From what I can gather I can check if its in the array and then push it with
if (!in_array( wControl, $arrLayout ))
array_push(..)
How would I code this correctly?
Thanks
<?php
/**
* #param array $sections
* #param string $name name of new key (like wControl)
* #param mixed $value value of new key
* #param string $into_section if empty, last section will be used
* #return bool
*/
function addUnique(array &$sections, $name, $value, $into_section = '')
{
$last_section = '';
foreach ($sections as $section_name => $section)
{
if (key_exists($name, $section)) return false;
$last_section = $section_name;
}
if (empty($into_section)) $into_section = $last_section;
$sections[$into_section][$name] = $value;
}
$arrLayout = array(
"section1" => array(
"wControl" => array(
"title" => "Control",
"display" => ""
),
"wRecentTV" => array(
"title" => "Recent TV",
"display" => ""
)
),
"section2" => array(
"wXBMCLibrary" => array(
"title" => "XBMC Library",
"display" => ""
)
),
"section3" => array(
"wSearch" => array(
"title" => "Search",
"display" => ""
),
"wRSS" => array(
"title" => "RSS Feed",
"display" => ""
)
),
);
$wControl = true;
if ($wControl)
{
addUnique($arrLayout, 'wControlNew', array(
"title" => "Control",
"display" => ""
),
'section2');
}
var_dump($arrLayout);

Categories