PHP multi-dimentional array condensing - php

I am using an array like this for a static file cache:
[
key => data => [
key1 => data => [...]
=> expires => 123456
key2 => data => [...]
=> expires => 123456
]
=> expires => 123456
]
This can be many levels deep (sometimes 10-15 levels).
What I would like to do is return only the values of data, so for instance, to create an array like so
[
key => key1 => [...]
=> key2 => [...]
]
how would I do this?
EDIT
print_r of the structure
Array (
[key] =>
Array (
[data] =>
Array (
[key1] =>
Array (
[data] => Array ( ... )
[expires] => 12345678)
[key2] =>
Array (
[data] => Array ( ... )
[expires] => 12345678
)
)
[expires] => 12345678
)
)

You can use recursive function like this:
function extractValues($array, &$result){
foreach($array as $key1 => $val1){
if($key1 == 'data' && is_array($val1)) {
foreach($val1 as $key2 => $val2){
if(is_array($val2)) {
$result[$key2] = array();
extractValues($val2, $result[$key2]);
} else {
$result[$key2] = $val2;
}
}
} else if(!in_array($key1, array('expires'))) {
$result[$key1] = array();
extractValues($val1, $result[$key1]);
}
}
return $result;
}
It will work on array structure like this:
$test = array(
'key' => array(
'data' => array(
'key1' => array(
'data' => array(
'key11' => 11,
'key12' => 12,
),
),
'key2' => array(
'data' => array(
'key21' => 21,
'key22' => 22,
),
),
),
'expires' => 12345,
),
);
$result = array();
extractValues($test, $result);
var_dump($result);
This is the result of the var_dump() hope meets your requirement:
array(1) {
["key"]=>
array(2) {
["key1"]=>
array(2) {
["key11"]=>
int(11)
["key12"]=>
int(12)
}
["key2"]=>
array(2) {
["key21"]=>
int(21)
["key22"]=>
int(22)
}
}
}

Related

Transform multiple values to single key

I am using php 7.1 and I have the following array:
<?php
$arr = array (
0 =>
array (
'Product' => 'Product1',
'Exact_Match_Keyword' => 'apples freshness',
),
1 =>
array (
'Product' => 'Product1',
'Exact_Match_Keyword' => 'apples',
),
2 =>
array (
'Product' => 'Product1',
'Exact_Match_Keyword' => 'oranges',
),
3 =>
array (
'Product' => 'Product2',
'Exact_Match_Keyword' => 'apples freshness',
),
4 =>
array (
'Product' => 'Product2',
'Exact_Match_Keyword' => 'apples',
),
);
$arr = array_merge_recursive($arr);
var_dump($arr);
/* WANTED DATA STRUCTURE
$arr = array (
0 =>
array (
'Product' => 'Product1',
'Exact_Match_Keyword' => array('apples freshness', 'apples', 'oranges'),
),
1 =>
array (
'Product' => 'Product2',
'Exact_Match_Keyword' => array('apples freshness', 'apples'),
),
);
*/
I tried to use array_merge_recursive however this does not give me my wanted data structure.
Any suggestions what I am doing wrong?
I appreciate your replies!
You can use array_reduce to handle simple logic like this for you. The example below will provide you with the expected format you've posted.
$example = array_values(
array_reduce(
$arr,
static function ($acc, $row) {
if (!isset($acc[$row['Product']])) {
$acc[$row['Product']] = [
'Product' => $row['Product'],
'Exact_Match_Keyword' => [$row['Exact_Match_Keyword']],
];
} else {
$acc[$row['Product']]['Exact_Match_Keyword'] = array_merge(
$acc[$row['Product']]['Exact_Match_Keyword'],
[$row['Exact_Match_Keyword']]
);
}
return $acc;
}
));
print_r($example);
It can be simplified further if the format you expect is flexible:
$example = array_reduce(
$arr,
static function ($acc, $row) {
if (!isset($acc[$row['Product']])) {
$acc[$row['Product']] = [$row['Exact_Match_Keyword']];
} else {
$acc[$row['Product']] = array_merge(
$acc[$row['Product']],
[$row['Exact_Match_Keyword']]
);
}
return $acc;
}
);
print_r($example);
//Output:
//[
// 'Product1'=> ['apples freshness', 'apples', 'oranges'],
// 'Product2'=> ['apples freshness', 'apples']
//]
I think this gets you what you want. Probably not the most graceful thing in the world but it's roughly the logic you'd want to follow.
$temp = [];
foreach ($arr as $v)
{
$pname = $v['Product'];
if (!isset($temp[$pname]))
{
$temp[$pname] = [];
}
$temp[$pname][] = $v['Exact_Match_Keyword'];
}
$out = [];
foreach ($temp as $k => $v)
{
$out[] = [
'Product' => $k,
'Exact_Match_Name' => $v
];
}
php > var_dump($out);
php shell code:1:
array(2) {
[0] =>
array(2) {
'Product' =>
string(8) "Product1"
'Exact_Match_Name' =>
array(3) {
[0] =>
string(16) "apples freshness"
[1] =>
string(6) "apples"
[2] =>
string(7) "oranges"
}
}
[1] =>
array(2) {
'Product' =>
string(8) "Product2"
'Exact_Match_Name' =>
array(2) {
[0] =>
string(16) "apples freshness"
[1] =>
string(6) "apples"
}
}
}
For future reference, if you would like to use the array_merge_recursive() approach on its own, the input data might have to be a little different from what I can tell.
After looking at the example in the documentation page for array_merge_recursive(), I wonder if the original input data needs to be structured a little differently. I think there needs to be matching inner array keys in order for the final array to have something to combine on for the various inner keys. In the example data below, I used the Products key to combine on for the first inner key.
I don't know if it's possible for your starting data to be structured differently for this process, but if the data could look like the following (based on the example on the documentation page for array_merge_recursive()):
<?php
$ar1 = array(
"Products" => array(
"Product1" => array(
"Exact_Match_Keyword" => array('apples freshness')
)
)
);
$ar2 = array(
"Products" => array(
"Product1" => array(
"Exact_Match_Keyword" => array('apples')
)
)
);
$ar3 = array(
"Products" => array(
"Product1" => array(
"Exact_Match_Keyword" => array('oranges')
)
)
);
$ar4 = array(
"Products" => array(
"Product2" => array(
"Exact_Match_Keyword" => array('apples freshness')
)
)
);
$ar5 = array(
"Products" => array(
"Product2" => array(
"Exact_Match_Keyword" => array('apples')
)
)
);
$result = array_merge_recursive($ar1, $ar2, $ar3, $ar4, $ar5);
print_r($result);
The output should then look like this:
Array
(
[Products] => Array
(
[Product1] => Array
(
[Exact_Match_Keyword] => Array
(
[0] => apples freshness
[1] => apples
[2] => oranges
)
)
[Product2] => Array
(
[Exact_Match_Keyword] => Array
(
[0] => apples freshness
[1] => apples
)
)
)
)

Grouped Array data

I'm trying to figure out how to get data from the following data structure. I managed to group a flat array into the following array, but am finding it difficult to find the proper resources to explain how to get the data out. I'm looking to get the count of the items in each group. Then i'd like to print the ids from the inner array...
array (
'grinds' =>
array (
0 =>
array (
'id' => 16562,
'slug' => 'grinds',
),
1 =>
array (
'id' => 16561,
'slug' => 'grinds',
),
),
'online-grinds' =>
array (
0 =>
array (
'id' => 16566,
'slug' => 'online-grinds',
),
),
)
$my_array1 = array(
'grinds' =>
array(
0 =>
array(
'id' => 16562,
'slug' => 'grinds',
),
1 =>
array(
'id' => 16561,
'slug' => 'grinds',
),
),
'online-grinds' =>
array(
0 =>
array(
'id' => 16566,
'slug' => 'online-grinds',
),
),
);
get counts:
$counts = array();
foreach ($my_array1 as $key => $val) {
$counts[$key] = count($val);
}
var_dump($counts);
yields:
array(2) {
["grinds"]=>
int(2)
["online-grinds"]=>
int(1)
}
get inner ids:
$innerids = array();
foreach ($my_array1 as $key => $val) {
foreach ($val as $key2 => $val2) {
$innerids[] = $val2['id'];
}
}
var_dump($innerids);
yields:
array(3) {
[0]=>
int(16562)
[1]=>
int(16561)
[2]=>
int(16566)
}
You could use array_map and then for every item use array_column and specifing the field name and then use array_count_values to count the unique values.
Then combine those in an array and use the existing key again as the key for then new array.
$arrays = array_map(function($x) {
return [
array_count_values(array_column($x, 'id')),
array_count_values(array_column($x, 'slug'))
];
}, $arrays);
print_r($arrays);
Result
Array
(
[grinds] => Array
(
[0] => Array
(
[16562] => 1
[16561] => 1
)
[1] => Array
(
[grinds] => 2
)
)
[online-grinds] => Array
(
[0] => Array
(
[16566] => 1
)
[1] => Array
(
[online-grinds] => 1
)
)
)
Demo

How to replace numeric keys in associative array with their corresponding values

I do have following associative multidimensional array available after json_decode(string, true).
Array
(
[statusCode] => 200
[data] => Array
(
[objects] => Array
(
[0] => deals
[1] => contacts
[2] => accounts
)
[deals] => Array
(
[0] => dealName
[1] => ApprovedBy
[2] => ApprovedDate
[3] => CloseDate
)
[contacts] => Array
(
[0] => contectName
[1] => email
[2] => firstName
[3] => lastName
)
[accounts] => Array
(
[0] => accountName
[1] => creationDate
[2] => ApprovedDate
[3] => accountNumber
)
)
)
It want to replace numeric keys with their corresponding values in arrays like:
[deals] => deals
[contacts] => contacts
[accounts] => accounts
What I tried so far?
$finalIOArray = array();
$integrationObjectsArray = $response['data']['objects'];
foreach($integrationObjectsArray as $integrationObject){
$finalIOArray[$integrationObject] = $integrationObject;
}
This is for only the objects array in the main data array. But I want to replace keys with values in all the sub-arrays in the main data array.
here's a recursive solution to the problem
function updateArray(array $data)
{
$result = array();
foreach ($data as $key => $value) {
if (is_integer($key) && is_string($value)) { // key is integer and value is string
$result[$value] = $value; // update the key
} elseif (is_array($value)) { // value is array
$result[$key] = updateArray($value); // recurse
} else {
$result[$key] = $value; // leave key/value alone
}
}
return $result;
}
print_r(updateArray($arr));
You can do like this
foreach($arr["data"] as $key=>&$data){
$new = array();
foreach($data as $key2=>$value){
$new[$value] = $value;
}
$data = $new;
}
print_r($arr);
Live demo : https://eval.in/858599
I modify my code to suits your needs, please, try it.
$data = [];
foreach($arr["data"] as $key => $example) {
$new = [];
foreach($example as $value) {
$new[$value] = $value;
}
$data[$key] = $new;
}
$arr["data"] = $data;
print_r($arr);
This is a cleaner and more direct method than the others on offer. Use array_combine to bulk reassign keys using values from the subarray.
In my method using foreach, the & before $data means "passing by reference" . http://php.net/manual/en/language.references.pass.php This effectively allows the modification of the original array data without writing the keys that lead to the specific deep element.
Code:
$arr = Array
(
"statusCode" => 200,
"data" => Array
(
"objects" => Array
(
"0" => deals,
"1" => contacts,
"2" => accounts
),
"deals" => Array
(
"0" => dealName,
"1" => ApprovedBy,
"2" => ApprovedDate,
"3" => CloseDate
),
"contacts" => Array
(
"0" => contectName,
"1" => email,
"2" => firstName,
"3" => lastName
),
"accounts" => Array
(
"0" => accountName,
"1" => creationDate,
"2" => ApprovedDate,
"3" => accountNumber
)
)
);
foreach($arr["data"] as &$data){
$data=array_combine($data,$data);
}
var_export($arr);
Output:
array (
'statusCode' => 200,
'data' =>
array (
'objects' =>
array (
'deals' => 'deals',
'contacts' => 'contacts',
'accounts' => 'accounts',
),
'deals' =>
array (
'dealName' => 'dealName',
'ApprovedBy' => 'ApprovedBy',
'ApprovedDate' => 'ApprovedDate',
'CloseDate' => 'CloseDate',
),
'contacts' =>
array (
'contectName' => 'contectName',
'email' => 'email',
'firstName' => 'firstName',
'lastName' => 'lastName',
),
'accounts' =>
array (
'accountName' => 'accountName',
'creationDate' => 'creationDate',
'ApprovedDate' => 'ApprovedDate',
'accountNumber' => 'accountNumber',
),
),
)
Or if you prefer functional iteration, this provides the same output.
$arr["data"]=array_map(function ($a){return array_combine($a,$a);},$arr["data"]);
var_export($arr);

PHP search multidimensional array with two keys for value of 3rd key?

I would think this is simple, searching a multidimensional array with two keys to bring back the value of the third. I'm more confused then when I started and unable to get it to work.
Array (
[0] => Array ( [data] => Array ( [name] => Definite Position [Company_ID] => 4 [code] => DEF ) )
[1] => Array ( [data] => Array ( [name] => First Option [Company_ID] => 7 [code] => TNT ) )
[2] => Array ( [data] => Array ( [name] => Second Option [Company_ID] => 4 [code] => SEC ) )
[3] => Array ( [data] => Array ( [name] => Definite Out [Company_ID] => 6 [code] => DBO ) )
I would like to bring back the value of [name] when I have [Company_ID] of 4 and [code] of 'SEC'
Any help would be appreciated. Thanks
It's just a simple loop accessing the data index and then the indexes below that:
$id = 4;
$code = 'SEC';
foreach($array as $values) {
if($values['data']['Company_ID'] == $id && $values['data']['code'] == $code) {
$result = $values['data']['name'];
break; // we found it no need to loop more
}
}
This might help:
<?php
$array = array(
array(
"data" => array(
"name" => "Definite Position",
"Company_ID" => 4,
"code" => "DEF"
)
),
array(
"data" => array(
"name" => "First Option",
"Company_ID" => 7,
"code" => "TNT"
)
),
array(
"data" => array(
"name" => "Second Option",
"Company_ID" => 4,
"code" => "SEC"
)
),
array(
"data" => array(
"name" => "Definite Out",
"Company_ID" => 6,
"code" => "DBO"
)
)
);
/**
* Searches the array for matching criteria
*
* #param array $search Array of criteria to search for (eg. array("Company_ID" => 4, "code" => "SEC"))
* #param array $array The array to search
*
* #return array The elements of the array that matched the criteria
*/
function search($search, $array)
{
$retVal = array();
foreach($array as $k => $v)
{
$found = true;
foreach($search as $sKey => $sVal)
{
if ($v["data"][$sKey] != $sVal)
{
$found = false;
break;
}
}
if ($found)
$retVal[]= $v;
}
return $retVal;
}
$results = search(
array(
"Company_ID" => 4,
"code" => "SEC"
),
$array
);
var_dump($results);
Result:
array(1) {
[0]=>
array(1) {
["data"]=>
array(3) {
["name"]=>
string(13) "Second Option"
["Company_ID"]=>
int(4)
["code"]=>
string(3) "SEC"
}
}
}

Multidimensional array remove inner array key based on condition

I have a array which i want to remove the first and second array from the array since status
is blank for first and second array .
The output should be
array([0]=> array (
[A] => 300000
[B] => jill
[status]=> "something"
)
)
any ideas to proceed?
array(
[0] => Array
(
[A] => 100000
[B] => jjohn
[status]=>
)
[1] => Array
(
[A] => 200000
[B] => jim
[status]=>
)
[2] => Array
(
[A] => 300000
[B] => jill
[status]=> "something"
)
)
$array = array_filter($array, function (array $i) { return $i['status']; });
This function checks if (bool)$item['status'] is evaluated as True, except
string '0'.
Function:
function ($item) {
return isset($item['status']) && ($item['status'] || is_string($item['status']));
}
Test Code:
$array = array(
array(
'Name' => 'Empty String',
'status' => '',
),
array(
'Name' => 'String Zero',
'status' => '0',
),
array(
'Name' => 'Integer Zero',
'status' => 0,
),
array(
'Name' => 'Bool False',
'status' => false,
),
array(
'Name' => 'NULL',
'status' => null,
),
array(
'Name' => 'Undefined',
),
);
$array = array_values(array_filter($array, function ($item) {
return isset($item['status']) && ($item['status'] || is_string($item['status']));
}));
var_dump($array);
Result:
array(1) {
[0]=>
array(2) {
["Name"]=>
string(11) "String Zero"
["status"]=>
string(1) "0"
}
}

Categories