PHP: Make an array clear? - php

I have an array like this:
array(
[cat] => news,
[comments_count] => 2,
[meta] => array(
[first_meta] => 44,
[second_meta] => 54,
)
)
The above code is an example of array that I have. Now I wanna make the above array clear like this:
array(
[cat] => news,
[comments_count] => 2,
[first_meta] => 44,
[second_meta] => 54,
)
(means Delete -meta- but not it's indexes. I want to add indexes of meta to the first array)

Add the meta array to the array and then unset the meta array:
$array = $array + $array['meta'];
unset($array['meta']);

You may use the below function if you have a multidimentional array and you can reuse it anywhere.
function array_flatten($array) {
if (!is_array($array)) {
return false;
}
$result = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
$result = array_merge($result, array_flatten($value));
} else {
$result[$key] = $value;
}
}
return $result;
}
$array = array(
'cat' => 'news',
'comments_count' => '2',
'meta' => array(
'first_meta' => '44',
'second_meta' => '54',
)
);
var_dump(array_flatten($array));
The result will be
array(4) {
["cat"]=>
string(4) "news"
["comments_count"]=>
string(1) "2"
["first_meta"]=>
string(2) "44"
["second_meta"]=>
string(2) "54"
}
Otherwise if you just need to flatten meta array as in your question. array_merge() the meta array and unset meta it as below.
$result = array_merge($array, $array["meta"]);
unset($result["meta"]);
var_dump($result);

Related

Filter array by keys and populate new multi-dimensional array from mutated keys and original values

I need to extract data from elements with keys that start with foo. from the below array:
[
'name' => 'Bar',
'location' => 'Baz',
'foo.2021-02-01' => '50000.00',
'foo.2021-03-01' => '50000.00',
'foo.2021-04-01' => '50000.00',
'foo.2021-05-01' => '',
]
After identifying qualifying keys, I need to create a new indexed array of associative rows using the date substring from the original keys like so:
[
['date' => '2021-02-01', 'value' => '50000.00'],
['date' => '2021-03-01', 'value' => '50000.00'],
['date' => '2021-04-01', 'value' => '50000.00'],
['date' => '2021-05-01', 'value' => ''],
]
I've been able to extract the keys like so:
$keys = array_keys($theData[0]);
foreach ( $keys as $key ) {
if ( preg_match( '/foo.*/', $key ) ) {
$line = explode('.', $key);
$item[]['name'] = $line[1];
}
}
but I'm losing the values.
I then tried looping through the array manually and rebuilding the desired outcome, but the keys will change so I don't know how future-proof that would be.
Is there a wildcard approach I can take to achieve this?
You almost had it:
<?php
$theData = [
'name' => 'Bar',
'location' => 'Baz',
'foo.2021-02-01' => '50000.00',
'foo.2021-03-01' => '50000.00',
'foo.2021-04-01' => '50000.00',
'foo.2021-05-01' => ''
];
$item = [];
// No need for array_keys(), foreach() can already do this
foreach( $theData as $key => $value )
{
// check if the key starts with foo.
// Regular expressions are heavy; if you'd like then substitute with:
// if ( substr( $key, 0, 4 ) === 'foo.' )
if ( preg_match( '/^foo\\./', $key ) )
{
// foo. is 4 chars long so substring from the fourth index till the end
$item[] = [
'date' => substr( $key, 4 ),
'value' => $value
];
}
}
var_dump( $item );
Output:
array(4) {
[0]=>
array(2) {
["date"]=>
string(10) "2021-02-01"
["value"]=>
string(8) "50000.00"
}
[1]=>
array(2) {
["date"]=>
string(10) "2021-03-01"
["value"]=>
string(8) "50000.00"
}
[2]=>
array(2) {
["date"]=>
string(10) "2021-04-01"
["value"]=>
string(8) "50000.00"
}
[3]=>
array(2) {
["date"]=>
string(10) "2021-05-01"
["value"]=>
string(0) ""
}
}
A simple loop, checking for the key starting with foo. and then a little code to replace foo. in the key with nothing will do the trick
If you have PHP8 or >
$arr = [
'name' => 'Bar',
'location' => 'Baz',
'foo.2021-02-01' => '50000.00',
'foo.2021-03-01' => '50000.00',
'foo.2021-04-01' => '50000.00',
'foo.2021-05-01' => ''
];
$new = [];
foreach ($arr as $k => $v){
if ( str_starts_with( $k , 'foo.' ) ) {
$new[] = ['date' => str_replace('foo.', '', $k), 'value' => $v];
}
}
print_r($new);
RESULT
Array
(
[0] => Array
([date] => 2021-02-01, [value] => 50000.00)
[1] => Array
([date] => 2021-03-01, [value] => 50000.00)
[2] => Array
([date] => 2021-04-01, [value] => 50000.00)
[3] => Array
([date] => 2021-05-01, [value] => )
)
Alternatively, for PHP versions prior to PHP8
$new = [];
foreach ($arr as $k => $v){
if ( strpos( $k , 'foo.') !== FALSE && strpos( $k , 'foo.') == 0 ) {
$new[] = ['date' => str_replace('foo.', '', $k), 'value' => $v];
}
}
Using str_starts_with and explode
$arr = [];
foreach ($theData as $k => $v){
if (str_starts_with($k, "foo."))
$arr[] = ["date" => explode(".", $k)[1], "value" => $v];
}
var_dump($arr);
sscanf() is an ideal function to call which will both check for qualifying strings and extract the desired trailing date value. It doesn't use regex, but it does require a placeholder %s to target the date substring. If a given string doesn't qualify, no element is pushed into the result array.
Code: (Demo) (without compact())
$result = [];
foreach ($array as $key => $value) {
if (sscanf($key, 'foo.%s', $date)) {
// $result[] = ['date' => $date, 'value' => $value];
$result[] = compact(['date', 'value']);
}
}
var_export($result);
If you remove the optional technique of using compact(), this solution makes fewer function calls than all other answers on this page.
I would probably only use regex if I wanted to strengthen the validation for qualifying key strings. (Demo)
$result = [];
foreach ($array as $key => $value) {
if (preg_match('~^foo\.\K\d{4}-\d{2}-\d{2}$~', $key, $m)) {
$result[] = ['date' => $m[0], 'value' => $value];
}
}
var_export($result);

How to find the value of a multidimensional array by key

How I can search array key from multidimensional array and return found key value with parent array key if it's exist. For example I've custom array:
$array = [
'type' => 'vacancy',
'needs' => ['root' => 'active'],
'market' => 'shopping',
'red' => 'color',
'education' => 'learning',
'fruits' => [
'red' => 'apple',
'cool' => 'cherry'
]
];
For example I need search key red from current array. As you see in this array exist 2 items with key red. If array have similar keys then function return example array as response:
[
0 => ['red' => 'color'],
1 => ['red' => 'apple']
]
If search key (example type) is only once inside array then response will be like this:
['type' => 'vacancy']
I tired:
function searchKey($key, $array) {
foreach ($array as $k => $v) {
if($key === $k) {
return [$k => $v];
} elseif(is_array($v)) {
return searchKey($key, $v);
} elseif(is_array($k)) {
return searchKey($key, $k);
}
}
return false;
}
When I search key root from array result is correct but when I searching key red return false. How can be solved my function or has any performance methods for searching key and get result for my needs?
You can try this :
function findByKey($findKey, $array, $result = []) {
foreach ($array as $key => $value) {
if ($key === $findKey) {
$result[] = [$key => $value];
}
if (is_array($value)) {
$result = findByKey($findKey, $value, $result);
}
}
return $result;
}
The idea is to use a recursive function :
you loop through your array
for each key => value, you check if the key is what you want : if yes, add it to the result array, else go next
if the value is an other array, you search inside this array if you have the key you want
Now use it :
$array = [
'type' => 'vacancy',
'needs' => ['root' => 'active'],
'market' => 'shopping',
'red' => 'color',
'education' => 'learning',
'fruits' => [
'red' => 'apple',
'cool' => 'cherry'
]
];
With key type :
$result = findByKey('type', $array);
var_dump($result);
Output is :
array(1) {
[0]=>
array(1) {
["type"]=>
string(7) "vacancy"
}
}
With key red :
$result = findByKey('red', $array);
var_dump($result);
Output is :
array(2) {
[0]=>
array(1) {
["red"]=>
string(5) "color"
}
[1]=>
array(1) {
["red"]=>
string(5) "apple"
}
}
Here is a link to test it : link

PHP - Get key value from other key

I have the following array:
$array = Array(
"0" => Array (
"id" => 1081,
"name" => "John"
),
"1" => Array (
"id" => 1082,
"name" => "Matt"
),
"2" => Array (
"id" => 1083,
"name" => "Roger"
)
);
Is there anyway I can get name if I only know the id but without having to iterate through the array?
For PHP >= 5.5.0:
$id = 1082;
$result = array_column($array, 'name', 'id')[$id];
As Barmar points out, to get an array that is easy to use with id as the index:
$id = 1082;
$result = array_column($array, 'name', 'id');
echo $result[$id];
You can make an associative array that refers to the same elements, then use that:
function make_assoc(&$array, $keyname) {
$new_array = array();
foreach ($array as &$elt) {
$new_array[$elt[$keyname]] = $elt;
}
return $new_array;
}
$assoc_array = make_assoc($array, 'id');
Now you can use $assoc_array[1083] to access the third item in the original array. And since this returns an array of references, modifying that will also modify the element of the original array.
You can use array_map to search into your array if your PHP < 5.5.0 and you don't have array_column:
<?php
$array = Array(
"0" => Array (
"id" => 1081,
"name" => "John"
),
"1" => Array (
"id" => 1082,
"name" => "Matt"
),
"2" => Array (
"id" => 1083,
"name" => "Roger"
)
);
$find = 1082;
$value = '';
$arr = array_map(function($n) use ($find, &$value) {if ($n['id'] == $find) $value = $n['name']; }, $array);
print_r($value);
?>

Multiple values from one loop php

If I have this array -
$data_item['actor_id'] = $this->input->post('actor_id');
$data_item['item_number'] = $this->input->post('item_number');
Which gives me this array -
Array (
[actor_id] => Array (
[0] => 162652153
[1] => 162652154
)
[item_number] => Array (
[0] => 3
[1] => 6
)
)
I need to get my data into this format -
$data = array(
array(
'actor_id' => '3342' ,
'item_number' => '57567'
),
array(
'actor_id' => '876' ,
'item_number' => '94'
)
);
I have tried various ways of looping through it but I can't seem to get it. Such as two seperate loops like this -
foreach($data_item['actor_id'] as $key => $value){
$thevalue[] = array('actor_id' => $value
);
}
But it is wrong format. Any tips please?
What about:
$d = [
'actor_id' => [
1,
2,
],
'item_number' => [
3,
4,
],
];
$res = [];
foreach ( $d as $key => $data ) {
foreach ( $data as $index => $value ) {
$res [ $index ] [$key] = $value;
}
}
I'll generate:
array(2) {
[0]=>
array(2) {
["actor_id"]=>
int(1)
["item_number"]=>
int(3)
}
[1]=>
array(2) {
["actor_id"]=>
int(2)
["item_number"]=>
int(4)
}
}
HTH
you can make use of the actor_id keys to flatten your data as desired:
$data = array(); // your new array
foreach($data_item['actor_id'] as $key => $value) {
// make sure we have an array for this key and add actor id
if (!isset($data[$key])) $data[$key] = array();
$data[$key]['actor_id'] = $value;
// now check if we have an item number for this key and add it
if (isset($data_item['item_number'][$key]))
$data[$key]['item_number'] = $data_item['item_number'][$key];
}
print_r($data);
The result should print out just as you wanted it. Sorry for not having tested the code my self, just typed it out of my head missing time and interpreter right now :)

recursive function php

I have an array which looks like this
$dataArray = array (
0 =>
array (
'UserId' => '804023',
'ProjectCode' => 'RA1234',
'Role' => 'PI',
),
1 =>
array (
'UserId' => '804023',
'ProjectCode' => 'RA1234',
'Role' => 'PM',
),
2 =>
array (
'UserId' => '804023',
'ProjectCode' => 'A90123',
'Role' => 'CI',
),
3 =>
array (
'UserId' => '804023',
'ProjectCode' => 'A20022',
'Role' => 'PM',
),
)
I need it to look like this
$expected = array (
804023 =>
array (
'RA1234' =>
array (
0 => 'PI',
1 => 'PM',
),
'A90123' =>
array (
0 => 'PI',
),
'A20022' =>
array (
0 => 'CI',
),
),
)
I think this could be achieved generically using recursion as this is a scenario I am likely to come across many times
I have got this far passing in an array of keys that form the nested array keys i.e.
$keys=array("UserId","projectCode","Role");
but am just not seeing where to go from here any pointers?
public function structureData(array $data, array $keys)
{
//$structuredData = array();
foreach ($data as $key => $value)
{
$keyForData = array_slice($keys,0,1);
$remainingKeys = $keys;
array_shift($remainingKeys);
if (!array_key_exists($value[$keyForData[0]], $structuredData))
{
$count=count($remainingKeys);
$structuredData[$value[$keyForData[0]]] =array();
// this returns as expected array(804023 =>array ()); but subsequent recursive calls with the remaining data fail
}
}
return $structuredData);
}
You don't need recursion, just a loop:
foreach ($dataArray as $da) {
$expected[$da['UserId']][$da['ProjectCode']][] = $da['Role'];
}
var_export($expected);
/* output:
array (
804023 =>
array (
'RA1234' =>
array (
0 => 'PI',
1 => 'PM',
),
'A90123' =>
array (
0 => 'CI',
),
'A20022' =>
array (
0 => 'PM',
),
),
)
*/
A crude but functioning solution.
function structureData($data, $keys){
$out = array();
foreach($data as $row){
$subout = &$out;
foreach(array_slice($keys, 0, -1) as $key){
$value = $row[$key];
$subout = &$subout[$value];
}
$subout[] = $row[$keys[count($keys) - 1]];
}
return $out;
}
print_r(structureData($dataArray, array('UserId', 'ProjectCode', 'Role')));
Recursion? Nah. Try this:
function add_role($dataArray, $userid, $project_code, $role)
{
$dataArray[$userid][$project_code][] = $role;
}
Functional solution:
$t = array_gather_key($dataArray, function ($e) { return $e['UserId']; } );
$t = array_map(
function ($e) {
return array_gather_key($e,
function ($e) { return $e['ProjectCode']; },
function ($e) { return $e['Role']; } );
},
$t
);
With this higher-order function:
function array_gather_key($array, $func, $transf = null) {
$res = array();
foreach ($array as $elem) {
$key = $func($elem);
if (!array_key_exists($key, $res))
$res[$key] = array();
if ($transf === null)
$res[$key][] = $elem;
else
$res[$key][] = $transf($elem);
}
return $res;
}
This gives:
array(1) {
[804023]=>
array(3) {
["RA1234"]=>
array(2) {
[0]=>
string(2) "PI"
[1]=>
string(2) "PM"
}
["A90123"]=>
array(1) {
[0]=>
string(2) "CI"
}
["A20022"]=>
array(1) {
[0]=>
string(2) "PM"
}
}
}

Categories