Converting array key to multidimensional array - php

I have an array like below
$db_resources = array('till' => array(
'left.btn' => 'Left button',
'left.text' => 'Left text',
'left.input.text' => 'Left input text',
'left.input.checkbox' => 'Left input checkbox'
));
I need to convert this array dynamically like below
'till' => array(
'left' => array(
'btn' => 'Left button',
'text' => 'Left text',
'input' => array(
'text' => 'Left input text',
'checkbox' => 'Left input checkbox'
)
)
)
I tried the key with explode. it works if all the key has only one ".". But the key has dynamic one. so please hep me to convert the array dynamically. I tried this Below Code
$label_array = array();
foreach($db_resources as $keey => $db_resources2){
if (strpos($keey,'.') !== false) {
$array_key = explode('.',$keey);
$frst_key = array_shift($array_key);
if(count($array_key) > 1){
$label_array[$frst_key][implode('.',$array_key)] = $db_resources2;
//Need to change here
}else{
$label_array[$frst_key][implode('.',$array_key)] = $db_resources2;
}
}
}

There might be more elegant ways to go about it, but here is one example of doing it with recursive helper function:
function generateNew($array, $keys, $currentIndex, $value)
{
if ($currentIndex == count($keys) - 1)
{
$array[$keys[$currentIndex]] = $value;
}
else
{
if (!isset($array[$keys[$currentIndex]]))
{
$array[$keys[$currentIndex]] = array();
}
$array[$keys[$currentIndex]] = generateNew($array[$keys[$currentIndex]], $keys, $currentIndex + 1, $value);
}
return $array;
}
$result = array();
// $temp equals your original value array here...
foreach ($temp as $combinedKey => $value)
{
$result = generateNew($result, explode(".", $combinedKey), 0, $value);
}

Related

Remove array key prefix recursively

I have an array in the following format (each child array has parent's key as a prefix):
$input = array(
'seo_text' => array(
'seo_text_title' => '',
'seo_text_description' => '',
'seo_text_button' => array(
'seo_text_button_text' => '',
'seo_text_button_url' => '',
'seo_text_button_new_tab_enabled' => '',
),
),
);
I want to convert it into the following format:
$input = array(
'seo_text' => array(
'title' => '',
'description' => '',
'button' => array(
'text' => '',
'url' => '',
'new_tab_enabled' => '',
),
),
);
I'm trying to write a recursive function, but it's not working the way it's suppose to be working.
A solution:
function removeKeyPrefix(array $array, string $prefix = ''): array
{
$newArray = [];
$prefixLength = strlen($prefix);
foreach ($array as $key => $value) {
if (substr($key, 0, $prefixLength) === $prefix) {
$newKey = substr($key, $prefixLength);
} else {
$newKey = $key;
}
$newArray[$newKey] = is_array($value) ? removeKeyPrefix($value, $key.'_') : $value;
}
return $newArray;
}
$input = removeKeyPrefix($input);
Online demo on 3v4l
function sanitizeKeys(array $items, $previousKey = '') : array
{
$previousKey .= "_";
return array_reduce(
array_keys($items),
function($result, $key) use ($previousKey, $items) {
$newKey = (0 === strpos($key, $previousKey)) ? substr_replace($key, '', 0, strlen($previousKey)) : $key;
$result[$newKey] = is_array($items[$key]) ? sanitizeKeys($items[$key], $key) : $items[$key];
return $result;
}, []
);
};
sanitizeKeys($input);
Make a function to change last occurrence in the slug
function fun($array,$slug){
foreach($array as $key=>$val){
$last = end(explode($slug,$key));
if(is_array($val)){
$val = fun($val,$key."_");
}
$array[$last] = $val;
unset($array[$key]);
}
return $array;
}
$input["seo_text"] = fun($input["seo_text"],"seo_text_");
print_r($input);
Live demo : https://eval.in/934155
Output is
Array
(
[seo_text] => Array
(
[title] =>
[description] =>
[button] => Array
(
[text] =>
[url] =>
[new_tab_enabled] =>
)
)
)
For if you have many element in second level use foreach to call function like below
foreach($input as $key=>$val){
$input[$key] = fun($val,$key."_");
}
print_r($input);
https://eval.in/934156

Extract array parts based on given keys in array

I have two arrays. One containing the data and other contains the keys. So I have
$data = array(
'name' => array('label' => 'Name:', 'value' => 'Genghis'),
'age' => array('label' => 'Age:', 'value' => '67'),
'weigh' => array('label' => 'Weigh in Kgs:', 'value' => '78')
);
and
$keys = array('name', 'age');
Now I want to extract only the name and age elements of $data. Some thing like this.
$extracted = somemethod($data, $keys);
var_export($extracted);
Output should be like this.
array(
'name' => array(
'label' => 'Name:',
'value' => 'Genghis',
),
'age' => array(
'label' => 'Age:',
'value' => '67',
),
)
How can i do this?
I would use an array_intersect_key() function like this:
$data = array(...); // initial array as described
$retained_keys = array('name' => 'value not used', 'age' => 'value not used');
$filtered_array = array_intersect_key($data, $retained_keys);
Loop over the keys, grab the array values, and return them:
function somemethod($data, $keys) {
$return = array();
foreach( $keys as $k) {
$return[$k] = isset( $data[$k]) ? $data[$k] : null;
}
return $return;
}
The above adds 'null' when a field isn't found. You can modify the foreach loop to just skip the key when it's not found in the $data array, like this:
function somemethod($data, $keys) {
$return = array();
foreach( $keys as $k) {
if( isset( $data[$k])) {
$return[$k] = $data[$k];
}
}
return $return;
}
Edit: To extend on Mike Brant's answer, array_intersect_key() can be used with array_flip() in a function to achieve the desired output:
function somemethod($data, $keys) {
$keys = array_flip( $keys);
return array_intersect_key($data, $keys);
}
Yes, it uses array_flip(), but the original $keys array is left unmodified, as a copy of that array is what gets flipped. So, you would still call this function with:
$extracted = somemethod( $data, array('name', 'age'));
Not exactly onerous to write
$extracted = array();
foreach($keys as $key) {
if (isset($data[$key]))
$extracted[$key] = $data[$key];
}

PHP - Arrays and Foreach

I searched in Google and consulted the PHP documentation, but couldn't figure out how the following code works:
$some='name=Licensing Module;nextduedate=2013-04-10;status=Active|name=Test Addon;nextduedate=2013-04-11;status=Active';
function getActiveAddons($somet) {
$addons = array( );
foreach ($somet as $addon) {
if ($addon['status'] == 'Active') {
$addons[] = $addon['name'];
continue;
}
}
return $addons;
}
echo (count( getActiveAddons( $some ) ) ? implode( '<br />', getActiveAddons( $some ) ) : 'None');
The code always echo's None.
Please help me in this.
I don't know where you got this code from but you've initialized $some the wrong way. It is expected as an array like this:
$some = array(
array(
'name' => 'Licensing Module',
'nextduedate' => '2013-04-10',
'status' => 'Active'
),
array(
'name' => 'Test Addon'
'nextduedate' => '2013-04-11',
'status' => 'Active'
)
);
I guess the article you've read is expecting you to parse the original string into this format.
You can achieve this like this:
$string = 'name=Licensing Module;nextduedate=2013-04-10;status=Active|name=Test Addon;nextduedate=2013-04-11;status=Active';
$result = array();
foreach(explode('|', $string) as $record) {
$item = array();
foreach(explode(';', $record) as $column) {
$keyval = explode('=', $column);
$item[$keyval[0]] = $keyval[1];
}
$result[]= $item;
}
// now call your function
getActiveAddons($result);
$some is not an array so foreach will not operate on it. You need to do something like
$some = array(
array(
'name' => 'Licensing Module',
'nextduedate' => '2013-04-10',
'status' => 'Active'
),
array(
'name' => 'Test Addon',
'nextduedate' => '2013-04-11',
'status'=> 'Active'
)
);
This will create a multidimensional array that you can loop through.
function getActiveAddons($somet) {
$addons = array( );
foreach ($somet as $addon) {
foreach($addon as $key => $value) {
if ($key == 'status' && $value == 'Active') {
$addons[] = $addon['name'];
continue;
}
}
}
return $addons;
}
First, your $some variable is just a string. You could parse the string into an array using explode(), but it's easier to just start as an array:
$some = array(
array(
"name" => "Licensing Module",
"nextduedate" => "2013-04-10",
"status" => "Active",
),
array(
"name" => "Test Addon",
"nextduedate" => "2013-04-11",
"status" => "Active",
)
);
Now, for your function, you are on the right track, but I'll just clean it up:
function getActiveAddons($somet) {
if (!is_array($somet)) {
return false;
}
$addons = array();
foreach ($somet as $addon) {
if ($addon['status'] == 'Active') {
$addons[] = $addon['name'];
}
}
if (count($addons) > 0) {
return $addons;
}
return false;
}
And finally your output (you were calling the function twice):
$result = getActiveAddons($some);
if ($result === false) {
echo "No active addons!";
}
else {
echo implode("<br />", $result);
}

Combine repeating elements as array in a multidimensional array

I was wondering when working with multimedional arrays, if a certain key is the same, is there a way to combine the contents of other keys into its own array if a certain key is the same?
Something like this:
// name is the same in both arrays
array(
array(
'name' => 'Pepsi',
'store' => 'Over here',
'number' => '1234567'
),
array(
'name' => 'Pepsi',
'store' => 'Over here',
'number' => '5556734'
)
)
into something like this
array(
array(
'name' => 'Pepsi',
'store' => array('Over here', 'Over here'),
'number' => array('1234567', '5556734')
)
)
The defining key is checking if the name element is the same for the other arrays.
You can try a function like this.
function mergeByKey($array,$key){
$tmp_array = array();
foreach ( $array as $k => $row ) {
$merged = false;
foreach ($tmp_array as $k2 => $tmp_row){
if ($row[$key] == $tmp_row[$key]){
foreach ( $row as $k3 => $value ) {
if ($k3 == $key) continue;
$tmp_array[$k2][$k3][] = $value;
$merged = true;
}
}
if ($merged) break;
}
if (!$merged) {
$new_row = array();
foreach ( $row as $k4 => $value ) {
if ($k4 == $key) $new_row[$k4] = $value;
else $new_row[$k4] = array($value);
}
$tmp_array[] = $new_row;
}
}
foreach ( $tmp_array as $t => $row ) {
foreach ( $row as $t2 => $value ) {
if ( count($value) == 1 && $t2 != $key ) $tmp_array[$t][$t2] = $value[0];
}
}
return $tmp_array;
}
passing the array as first parameter and the key as second one.
I'm referencing to your array structure
edited: missed a piece
edited2: if resultin array contains elements with one string, it returns a string and not a array with one element
demo
This function uses a given field name as the grouping identifier and turns all other fields into arrays.
Note that single occurrences of your field name will yield arrays with a single element for the other fields. I wasn't sure whether that's a desirable trait, but just making sure you know ;-)
$arr = array(
array(
'name' => 'Pepsi',
'store' => 'Over here',
'number' => '1234567'
),
array(
'name' => 'Pepsi',
'store' => 'Over here',
'number' => '5556734'
)
);
function mergeArray($array, $column)
{
$res = array();
foreach ($array as $item) {
foreach ($item as $key => $value) {
if ($key === $column) {
$res[$column][$key] = $value;
} else {
$res[$column][$key][] = $value;
}
}
}
return array_values($res);
}
print_r(mergeArray($arr, 'name'));
Demo
Thanks to Gianni Lovece for her answer but I was able to develop a much simpler solution based on this problem. Just plug in the $result_arr to browse through and the $key you want to use as basis and it immediately outputs a multidimensional array with non-repeating values for repeating elements (see example below).
function multiarray_merge($result_arr, $key){
foreach($result_arr as $val){
$item = $val[$key];
foreach($val as $k=>$v){
$arr[$item][$k][] = $v;
}
}
// Combine unique entries into a single array
// and non-unique entries into a single element
foreach($arr as $key=>$val){
foreach($val as $k=>$v){
$field = array_unique($v);
if(count($field) == 1){
$field = array_values($field);
$field = $field[0];
$arr[$key][$k] = $field;
} else {
$arr[$key][$k] = $field;
}
}
}
return $arr;
}
For example, in the sample array for this question, running multiarray_merge($mysample, 'name') returns
array(
'Pepsi' => array(
'name' => 'Pepsi',
'store' => 'Over here', // String: Not an array since values are not unique
'number' => array('1234567', '5556734') // Array: Saved as array since values are unique
)
);

String to variable-depth multidimensional array

I'm trying to create a multidimensional array from a string (received from $_GET, input is validated, but not in this example). Each '-' will indicate a level in the multidimensional array.
Values can look like this (any form really, as long as '-' is present between keys). The array of values can map to any depth in the multidimensional array.
$array = array(
'page-title' => 'Title of a page',
'page-url' => 'http://www.mypage.com',
'meta-page-author' => 'Some guy',
'meta-page-created' => 'some timestamp'
);
I've tried different solutions, but the only thing working until now is the inital loop and extract of keys.
foreach ($array as $key => $value) {
if (strpos($key, '-') !== false) {
$keyArray = explode('-', $key);
// ??
}
}
The output I'm hoping for, should look like this:
array(
'page' => array(
'title' => 'Title of a page',
'url' => 'http://www.mypage.com'
),
'meta' => array(
'page' => array(
'author' => 'Some guy',
'created' => 'some timestamp'
)
)
);
Something like this should work:
<?php
$array = array(
'page-title' => 'Title of a page',
'page-url' => 'http://www.mypage.com',
'meta-page-author' => 'Some guy',
'meta-page-created' => 'some timestamp'
);
$result = array();
foreach ($array as $key => $value) {
$keys = strpos($key, '-') !== false ? explode('-', $key) : array($key);
$ptr = &$result;
foreach ($keys as $k) {
if (!isset($ptr[$k])) {
$ptr[$k] = array();
}
$ptr = &$ptr[$k];
}
if (empty($ptr)) {
$ptr = $value;
} else {
$ptr[] = $value;
}
}
print_r($result);
What I did was explode your keys just like you were doing. I then looped through them creating a new array if the array didn't already exist. Using a reference I save the current point I was at in the array. Then once I had hit the last key I assigned the value. Hope this helps.
EDIT: Based on cHao's recommendation I changed
$keys = strpos($key, '-') !== false ? explode('-', $key) : $key;
to
$keys = strpos($key, '-') !== false ? explode('-', $key) : array($key);
to prevent failure on the foreach.
EDIT 2: I changed
$ptr = $value;
to
if (empty($ptr)) {
$ptr = $value;
} else {
$ptr[] = $value;
}
to handle cases like:
$array = array(
'page-title' => 'Title of a page',
'page-url' => 'http://www.mypage.com',
'meta-page-author' => 'Some guy',
'meta-page-created' => 'some timestamp',
'page' => 'foo'
);
Just so you're aware, PHP can be made to accept whole big arrays like that. If you name the form elements like 'somename[page][title]', then when the form returns, you should see them already arranged as an array in $_GET.
In case you have your heart set on the current naming scheme, though...
$result = array();
foreach ($array as $key => $value) {
$current =& $result;
if (strpos($key, '-') !== false) {
$keyArray = explode('-', $key);
$bottomKey = array_pop($keyArray);
foreach ($keyArray as $subKey) {
if (!isset($current[$subKey]))
$current[$subKey] = array();
$current =& $current[$subKey];
}
} else {
$bottomKey = $key;
}
$current[$bottomKey] = $value;
}
<?php
$array = array(
'page-title' => 'Title of a page',
'page-url' => 'http://www.mypage.com',
'meta-page-author' => 'Some guy',
'meta-page-created' => 'some timestamp'
);
$result = array();
foreach ($array as $key => $value) {
if (strpos($key, '-') !== false) {
$ak = "result['" . str_replace('-', '\'][\'', $key) . "'] = \"".$value."\"";
eval('$'.$ak.';');
}
}
var_dump($result);
?>
hope that helps

Categories