I need to extract a associative array keys into a string and implode with "/" or any character/symbols.
For eg:
$array = array([key1] =>
array([key11] =>
array([key111] => 'value111',
[key112] => 'value112',
[key113] => 'value113',
),
),
);
I need an output as below array:
array([0] => 'key1/key11/key111',[1] => 'key1/key11/key112', [2] => 'key1/key11/key112');
I've edited an answer given here and came up with the following code.
function listArrayRecursive($someArray, &$outputArray, $separator = "/") {
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($someArray), RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $k => $v) {
if (!$iterator->hasChildren()) {
for ($p = array(), $i = 0, $z = $iterator->getDepth(); $i <= $z; $i++) {
$p[] = $iterator->getSubIterator($i)->key();
}
$path = implode($separator, $p);
$outputArray[] = $path;
}
}
}
$outputArray = array();
listArrayRecursive($array, $outputArray);
print_r($outputArray);
Input:
Array
(
[key1] => Array
(
[key11] => Array
(
[key111] => value111
[key112] => value113
[key113] => value113
)
)
)
Output:
Array
(
[0] => key1/key11/key111
[1] => key1/key11/key112
[2] => key1/key11/key113
)
Works for different depth of array:
function getKeys($array, $prefix='', $separator = '/') {
$return = array();
foreach($array as $key => $value) {
if (!is_array($value)) $return[] = $prefix . $key;
else $return = array_merge($return, getKeys($value, $prefix . $key . separator), $separator);
}
return $return;
}
$keys = getKeys($array, '', '#');
See online fiddle http://ideone.com/krU4Xn
you could do something like...
$mapArray = array();
$symbol = '/';
foreach($array as $k =>$v)
foreach($v as $k1 =>$v1)
foreach($v1 as $k2 =>$v2)
$mapArray[] = $k.$symbol.$k1.$symbol.$k2;
also this obviously only works in this particular case, if it needs to be more generic it can be done, but I think this should get you started.
Related
I am looking to store sum of all keys inside an array here is my example code
<?php
// Sample data
$category = (object) ['category_name' => '32459*1500*lab*1,32460*400*lab*1,32461*600*lab*1'];
// process
$category_sale_data = explode(',', $category->category_name);
foreach ($category_sale_data as $key => $value) {
list($sale_key, $sale_value) = explode('*', $value);
$category->sale_data[$sale_key][] = $sale_value;
//$category->sale_data_sum[$sale_key][] += $sale_value;
}
// display
print_r($category);
getting this output working example -> https://3v4l.org/NAKfb#v7.0.0
Here is expected to get //$category->sale_data_sum[$sale_key][] +=
$sale_value;
I am expected output like this
stdClass Object
(
[category_name] => 32459*1500*lab*1,32460*400*lab*1,32461*600*lab*1
[sale_data] => Array
(
[32459] => Array
(
[0] => 1500
)
[32460] => Array
(
[0] => 400
)
[32461] => Array
(
[0] => 600
)
)
[sale_data_sum] => 2500
)
Simply do this:
$category->sale_data_sum = 0; // initiate key
foreach ($category_sale_data as $key => $value) {
list($sale_key, $sale_value) = explode('*', $value);
$category->sale_data[$sale_key][] = $sale_value;
$category->sale_data_sum += $sale_value; // add each sale value
}
$category = [ 'category_name' => '32459*1500*lab*1,32460*400*lab*1,32461*600*lab*1' ];
// category_name
$result['category_name'] = $category['category_name'];
// sale_data
$splitted = preg_split('/[*,]/', $category['category_name']);
for($i = 0; $i < count($splitted); $i += 4) {
$result['sale_data'][$splitted[$i]] = $splitted[$i + 1];
}
// sale_data_sum
$result['sale_data_sum'] = array_sum($result['sale_data']);
print_r($result);
Try this
<?php
// Sample data
$category = (object) ['category_name' => '32459*1500*lab*1,32460*400*lab*1,32461*600*lab*1'];
// process
$category_sale_data = explode(',', $category->category_name);
foreach ($category_sale_data as $key => $value) {
list($sale_key, $sale_value) = explode('*', $value);
$category->sale_data[$sale_key][] = $sale_value;
//$category->sale_data_sum[$sale_key][] += $sale_value;
}
function sum($carry, $item)
{
$carry += array_values($item)[0];
return $carry;
}
$a = array_reduce(array_values($category->sale_data), "sum");
var_dump($a);
Or
<?php
// Sample data
$category = (object) ['category_name' => '32459*1500*lab*1,32460*400*lab*1,32461*600*lab*1'];
// process
$category_sale_data = explode(',', $category->category_name);
$category->sale_data_sum = null;
foreach ($category_sale_data as $key => $value) {
list($sale_key, $sale_value) = explode('*', $value);
$category->sale_data[$sale_key][] = $sale_value;
$category->sale_data_sum += $sale_value;
}
// display
print_r($category);
I am stuck with a part of my code and i can't see to figure out why i get a certain result. What my goal is to loop through the array and echo this result as a string:
First Array
validate.required
validate.remote
Second array
shop.cart.string
Current result is:
validate.0.required
validate.1.remote
It returns the index from the array, how can solve this/remove this from my string?
private $translationKeys = [
'validate' => [
'required',
'remote',
'email',
'url',
'date',
'dateISO',
'number',
'digits',
'creditcard',
'equalTo',
'extension',
'maxlength',
'minlength',
'rangelength',
'range',
'max',
'min',
'step'
],
'shop' => [
'cart' => [
'string'
],
],
];
This is my function:
function listArrayRecursive($translationKeys) {
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($translationKeys), RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $k => $v) {
if ($iterator->hasChildren()) {
} else {
for ($p = array(), $i = 0, $z = $iterator->getDepth(); $i <= $z; $i++) {
$p[] = $iterator->getSubIterator($i)->key();
$y = array();
foreach ($p as $value) {
array_push($y, $value);
}
}
$path = implode('.', $y);
$a[] = "$path.$v<br>";
// Here i want to echo the string
}
}
}
Second version of the function
function listArrayRecursive($translationKeys) {
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($translationKeys), RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $k => $v) {
if ($iterator->hasChildren()) {
} else {
for ($p = array(), $i = 0, $z = $iterator->getDepth(); $i <= $z; $i++) {
$p[] = $iterator->getSubIterator($i)->key();
}
$path = implode('.', $p);
$a[] = "$path.$v<br>";
}
}
}
Here's a function that will give you the result you desire. It recurses through each element of the array that is an array, concatenating the key with the values, or just returns the value if it is not an array:
function listArrayRecursive($array) {
$list = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
foreach (listArrayRecursive($value) as $v) {
$list[] = "$key.$v";
}
}
else {
$list[] = $value;
}
}
return $list;
}
print_r(listArrayRecursive($translationKeys));
Output:
Array (
[0] => validate.required
[1] => validate.remote
[2] => validate.email
[3] => validate.url
[4] => validate.date
[5] => validate.dateISO
[6] => validate.number
[7] => validate.digits
[8] => validate.creditcard
[9] => validate.equalTo
[10] => validate.extension
[11] => validate.maxlength
[12] => validate.minlength
[13] => validate.rangelength
[14] => validate.range
[15] => validate.max
[16] => validate.min
[17] => validate.step
[18] => shop.cart.string
)
Demo on 3v4l.org
try something like this
function disp_array_rec($arr, $upper = null) {
foreach ($arr as $k => $v) {
echo ($upper != null ? $upper : "");
if (is_array($v)) {
disp_array_rec($v, $k . ".");
} else {
echo "$v\n";
}
}
}
disp_array_rec($translationKeys);
result:
validate.required
validate.remote
validate.email
validate.url
validate.date
validate.dateISO
validate.number
validate.digits
validate.creditcard
validate.equalTo
validate.extension
validate.maxlength
validate.minlength
validate.rangelength
validate.range
validate.max
validate.min
validate.step
shop.cart.string
So I've got a list of paths, such as:
path/to/directory/file1
path/directory/file2
path2/dir/file3
path2/dir/file4
And I'd like to convert them into a multidimensional array like this:
array(
path => array(
to => array(
directory => array(
file1 => someValue
),
),
directory => array(
file2 => someValue
),
),
path2 => array(
dir => array(
file3 => someValue,
file4 => someValue
)
)
)
My first thought was to explode() the paths into segments and set up the array using a foreach loop, something like this:
$arr = array();
foreach ( $path as $p ) {
$segments = explode('/', $p);
$str = '';
foreach ( $segments as $s ) {
$str .= "[$s]";
}
$arr{$str} = $someValue;
}
But this doesn't work, and since the number of segments varies, I've kinda got stumped. Is there away to do this?
If somevalue can be an empty array:
<?php
$result = array();
$input = [
'path/to/directory/file1',
'path/directory/file2',
'path2/dir/file3',
'path2/dir/file4',
];
foreach( $input as $e ) {
nest( $result, explode('/', $e));
}
var_export($result);
function nest(array &$target, array $parts) {
if ( empty($parts) ) {
return;
}
else {
$e = array_shift($parts);
if ( !isset($target[$e]) ) {
$target[$e] = [];
}
nest($target[$e], $parts);
}
}
Here is the solution and a easy way
Just Reverse the whole exploded array and start creating array within a Array
$path[1] = "path/to/directory/file1";
$path[2] = "path/directory/file2";
$path[3] = "path2/dir/file3";
$path[4] = "path2/dir/file4";
$arr = array();
$b = array();
$k = 0;
foreach($path as $p) {
$c = 0;
$segments = explode('/', $p);
$reversed = array_reverse($segments);
foreach($reversed as $s) {
if ($c == 0) {
$g[$k] = array($s => "somevalue");
} else {
$g[$k] = array($s => $g[$k]);
}
$c++;
}
$k++;
}
var_dump($g);
Thanks so much VolkerK! Your answer didn't quite answer my question but it got me on the right track. Here's the version I ended up using to get it to work:
$result = array();
$input = [
'path/to/directory/file1' => 'someValue',
'path/directory/file2' => 'someValue',
'path2/dir/file3' => 'someValue',
'path2/dir/file4' => 'someValue',
];
foreach( $input as $e=>$val ) {
nest( $result, explode('/', $e), $val);
}
var_export($result);
function nest(array &$target, array $parts, $leafValue) {
$e = array_shift($parts);
if ( empty($parts) ) {
$target[$e] = $leafValue;
return;
}
if ( !isset($target[$e]) ) {
$target[$e] = [];
}
nest($target[$e], $parts, $leafValue);
}
I basically just added the somevalue as $leafValue and moved the base case around so that it would add the leafValue instead of a blank array at the end.
This results in:
Array
(
[path] => Array
(
[to] => Array
(
[directory] => Array
(
[file1] => someValue
)
)
[directory] => Array
(
[file2] => someValue
)
)
[path2] => Array
(
[dir] => Array
(
[file3] => someValue
[file4] => someValue
)
)
)
Thanks a lot!
It can be done without recursion
$path = array(
'path/to/directory/file1',
'path/directory/file2',
'path2/dir/file3',
'path2/dir/file4');
$arr = [];
$someValue = 'someValue';
foreach ( $path as $p ) {
$segments = explode('/', $p);
$str = '';
$p = &$arr;
foreach ( $segments as $s ) {
if (! isset($p[$s] ) ) $p[$s] = array();
$p = &$p[$s];
}
$p = $someValue;
}
print_r($arr);
I have an array that looks like this:
$array = array (
[level_1] => array (
[level_2] => array (
[level_3] => something
)
),
[level_12] => array (
[level_2] => somethingelse
),
[level_13] => array (
[level_22] => array (
[level_3] => something
)
),
);
The keys or values aren't always unique but the branches are.
And I have a string that looks like this:
$string = 'level_1-level_2-level_3';
Those are the keys for a branch.
And I need to somehow get the value from the array based on that string?
Like this:
$string_array = explode('-', $string);
$array[$string_array[0]][$string_array[1]][$string_array[2]] // something
But since the depth can be different this is not a viable solution...
Try this simple example, no need for a recursive function:
function get_item( $path, $array )
{
$paths = explode( '-', $path );
$result = $array;
foreach ( $paths as $path) {
isset( $result[$path] ) ? $result = $result[$path] : $result = false;
}
return $result;
}
$path = 'level_1-level_2-level_3';
echo get_item( $path, $array );
Try this:
$array = array (
'level_1' => array (
'level_2' => array (
'level_3' => 'something'
)
),
'level_12' => array (
'level_2' => 'somethingelse'
),
'level_13' => array (
'level_22' => array (
'level_3' => 'something'
)
),
);
$string = 'level_1-level_2-level_3';
$keys = explode('-', $string);
echo getItemIterative($keys, $array);
echo "\n";
echo getItemRecursive($keys, $array);
function getItemIterative($keys, $array)
{
$value = null;
foreach ($keys as $key) {
if ($value == null) {
$value = $array[$key];
}
if (is_array($value) && array_key_exists($key, $value)) {
$value = $value[$key];
}
}
return $value;
}
function getItemRecursive($keys, $array)
{
$key = array_shift($keys);
$value = $array[$key];
if (empty($keys)) {
return $value;
} else {
return getItemRecursive($keys, $value);
}
}
Make a $result variable which initially points to the root of the array, and loop through the levels of your $string_array 'til $result points at the leaf you were looking for.
// stuff you already have:
$array = array(...); // your big array
$string = 'level_1-level_2-level_3';
$string_array = explode('-', $string);
// new stuff:
$result = $array;
foreach ($string_array as $level) {
$result = $result[$level];
}
echo $result; // 'something'
Working example: Ideone
In an array such as the one below, how could I rename "fee_id" to "id"?
Array
(
[0] => Array
(
[fee_id] => 15
[fee_amount] => 308.5
[year] => 2009
)
[1] => Array
(
[fee_id] => 14
[fee_amount] => 308.5
[year] => 2009
)
)
foreach ( $array as $k=>$v )
{
$array[$k] ['id'] = $array[$k] ['fee_id'];
unset($array[$k]['fee_id']);
}
This should work
You could use array_map() to do it.
$myarray = array_map(function($tag) {
return array(
'id' => $tag['fee_id'],
'fee_amount' => $tag['fee_amount'],
'year' => $tag['year']
); }, $myarray);
$arrayNum = count($theArray);
for( $i = 0 ; $i < $arrayNum ; $i++ )
{
$fee_id_value = $theArray[$i]['fee_id'];
unset($theArray[$i]['fee_id']);
$theArray[$i]['id'] = $fee_id_value;
}
This should work.
Copy the current 'fee_id' value to a new key named 'id' and unset the previous key?
foreach ($array as $arr)
{
$arr['id'] = $arr['fee_id'];
unset($arr['fee_id']);
}
There is no function builtin doing such thin afaik.
This is the working solution, i tested it.
foreach ($myArray as &$arr) {
$arr['id'] = $arr['fee_id'];
unset($arr['fee_id']);
}
The snippet below will rename an associative array key while preserving order (sometimes... we must). You can substitute the new key's $value if you need to wholly replace an item.
$old_key = "key_to_replace";
$new_key = "my_new_key";
$intermediate_array = array();
while (list($key, $value) = each($original_array)) {
if ($key == $old_key) {
$intermediate_array[$new_key] = $value;
}
else {
$intermediate_array[$key] = $value;
}
}
$original_array = $intermediate_array;
Converted 0->feild0, 1->field1,2->field2....
This is just one example in which i get comma separated value in string and convert it into multidimensional array and then using foreach loop i changed key value of array
<?php
$str = "abc,def,ghi,jkl,mno,pqr,stu
abc,def,ghi,jkl,mno,pqr,stu
abc,def,ghi,jkl,mno,pqr,stu
abc,def,ghi,jkl,mno,pqr,stu;
echo '<pre>';
$arr1 = explode("\n", $str); // this will create multidimensional array from upper string
//print_r($arr1);
foreach ($arr1 as $key => $value) {
$arr2[] = explode(",", $value);
foreach ($arr2 as $key1 => $value1) {
$i =0;
foreach ($value1 as $key2 => $value2) {
$key3 = 'field'.$i;
$i++;
$value1[$key3] = $value2;
unset($value1[$key2]);
}
}
$arr3[] = $value1;
}
print_r($arr3);
?>
I wrote a function to do it using objects or arrays (single or multidimensional) see at https://github.com/joaorito/php_RenameKeys.
Bellow is a simple example, you can use a json feature combine with replace to do it.
// Your original array (single or multi)
$original = array(
'DataHora' => date('YmdHis'),
'Produto' => 'Produto 1',
'Preco' => 10.00,
'Quant' => 2);
// Your map of key to change
$map = array(
'DataHora' => 'Date',
'Produto' => 'Product',
'Preco' => 'Price',
'Quant' => 'Amount');
$temp_array = json_encode($original);
foreach ($map AS $k=>$v) {
$temp_array = str_ireplace('"'.$k.'":','"'.$v.'":', $temp);
}
$new_array = json_decode($temp, $array);
Multidimentional array key can be changed dynamically by following function:
function change_key(array $arr, $keySetOrCallBack = [])
{
$newArr = [];
foreach ($arr as $k => $v) {
if (is_callable($keySetOrCallBack)) {
$key = call_user_func_array($keySetOrCallBack, [$k, $v]);
} else {
$key = $keySetOrCallBack[$k] ?? $k;
}
$newArr[$key] = is_array($v) ? array_change_key($v, $keySetOrCallBack) : $v;
}
return $newArr;
}
Sample Example:
$sampleArray = [
'hello' => 'world',
'nested' => ['hello' => 'John']
];
//Change by difined key set
$outputArray = change_key($sampleArray, ['hello' => 'hi']);
//Output Array: ['hi' => 'world', 'nested' => ['hi' => 'John']];
//Change by callback
$outputArray = change_key($sampleArray, function($key, $value) {
return ucwords(key);
});
//Output Array: ['Hello' => 'world', 'Nested' => ['Hello' => 'John']];
I have been trying to solve this issue for a couple hours using recursive functions, but finally I realized that we don't need recursion at all. Below is my approach.
$search = array('key1','key2','key3');
$replace = array('newkey1','newkey2','newkey3');
$resArray = str_replace($search,$replace,json_encode($array));
$res = json_decode($resArray);
On this way we can avoid loop and recursion.
Hope It helps.