I have a array multi level
$array = array("14529" => array("900" => array("87" => array() ) ) );
print_r(array_keys($array)); // result array("14529");
How to merge this array to single array
$array = array("14529", "900", "87");
Here is a function that does what you want. It is done recursively, so it doesn't matter how deep the array is.
function mergeArrayMultiKeyToSingleArray($array, $result=[])
{
foreach($array as $key => $value) {
$result[] = $key;
if(is_array($value)) {
$result = mergeArrayMultiKeyToSingleArray($value, $result);
}
}
return $result;
}
// USAGE:
$array = array("14529" => array("900" => array("87" => array() ) ) );
$array = mergeArrayMultiKeyToSingleArray($array);
// $array is now ["14529", "900", "87"]
The solution using RecursiveIteratorIterator class:
$arr = ["14529" => ["900" => ["87" => [] ] ] ];
$keys = [];
foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator($arr), RecursiveIteratorIterator::SELF_FIRST) as $k => $v) {
$keys[] = $k;
}
print_r($keys);
The output:
Array
(
[0] => 14529
[1] => 900
[2] => 87
)
I did this using class
class ArrayStripper
{
private $items = [];
public function strip($arrayOrItem)
{
if(is_array($arrayOrItem))
{
foreach ($arrayOrItem as $item)
{
$this->strip($item);
}
}
else
{
$this->items[] = $arrayOrItem;
}
}
public function get()
{
return $this->items;
}
}
$array = [1 , [2,3] , 4 , [[5 , 6 , 7] , [8 ,9] , 10]];
$stripper = new ArrayStripper();
$stripper->strip($array);
var_dump($stripper->get());
Related
I have a multidimensional array like this:
array (
level1 => array ( level1.1,
level1.2)
level2 => array ( level2.1,
level2.2 => array( level2.2.1 => 'foo',
level2.2.2 => 'bar',
level2.2.3 => 'test')
)
)
As a result I want an array of strings like this
array ("level1/level1.1",
"level1/level1.2",
"level2/level2.1",
"level2/level2.2/level2.2.1",
"level2/level2.2/level2.2.2",
"level2/level2.2/level2.2.3")
Here is the code I tried
function displayArrayRecursively($array, string $path) : array {
if($path == "")
$result_array = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
$this->displayArrayRecursively($value, $path . $key . '/');
} else {
$result_array[] = $path . $key; }
}
return $result_array;
}
Any idea how I can achieve this. I could use a reference array to populate, but I want to solve it with return values.
$array = [
'level1' => [
'level1.1',
'level1.2'
],
'level2' => [
'level2.1',
'level2.2' => [
'level2.2.1' => 'foo',
'level2.2.2' => 'bar',
'level2.2.3' => 'test'
]
]
];
function arrayParser(array $array, ?string $path=null) {
$res = [];
foreach($array as $key => $value) {
if(is_array($value)) {
$res[] = arrayParser($value, ($path ? $path.'/' : $path).$key);
}
else {
$res[] = $path.'/'.(!is_numeric($key) ? $key : $value);
}
}
return flatten($res);
}
function flatten(array $array) {
$return = array();
array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
return $return;
}
$res = arrayParser($array); // result
I have an array:
$arr = [
['id'=>1, 'name'=>'Peter', 'age'=>28],
['id'=>1, 'name'=>'David', 'age'=>28],
['id'=>2, 'name'=>'John', 'age'=>34],
['id'=>3, 'name'=>'Smith', 'age'=>36],
['id'=>3, 'name'=>'Smith', 'age'=>28],
];
I want filter it by column 'id', and merge the different values. I need output:
$arr = [
['id'=>1, 'name'=>'Peter,David', 'age'=>28],
['id'=>2, 'name'=>'John', 'age'=>34],
['id'=>3, 'name'=>'Smith', 'age'=>'36,28']
];
Is there any PHP function (such as: array_filter, array_walk, array_map,...) to do that, without looping code as below?
function combine_row($arr){
$last = null;
foreach ($arr as $key => $a){
if ($a['id']==$last['id']){
foreach ($a as $k=>$v) {
if($v!==$last[$k]) {
$arr[$key][$k].=','.$last[$k];
}
}
unset($arr[$key-1]);
}
$last = $a;
}
return $arr;
}
Thanks for helping me!
Here is a solution that uses a more functional style. Basically just a lot of the built-in array_* functions. This will ensure less side-effects, making your code less error prone.
The code first finds all unique _id_s. It then filters through the data and joins it in the end.
$result = array_map(
function ($id) use ($arr) {
return array_map(function ($data) {
if (is_array($data)) return join(",", array_unique($data));
return $data;
}, array_reduce(
array_filter($arr, function ($item) use ($id) { return $id === $item["id"]; }),
function ($result, $set) { return $result = array_filter(array_merge_recursive($result, $set)); }, [ ]
)
);
},
array_unique(array_column($arr, "id"))
);
print_r($result);
Output:
Array
(
[0] => Array
(
[id] => 1
[name] => Peter,David
[age] => 28
)
[2] => Array
(
[id] => 2
[name] => John
[age] => 34
)
[3] => Array
(
[id] => 3
[name] => Smith
[age] => 36,28
)
)
Using a chainable apigithub you can achieve much more readable code:
$result = arr($arr)
->column("id")
->unique()
->map(
function ($id) use ($arr) {
return arr($arr)
->filter(function ($item) use ($id) { return $id === $item["id"]; })
->reduce(function ($result, $set) { return array_filter(array_merge_recursive($result, $set)); }, [])
->map(function ($data) {
if (is_array($data)) return arr($data)->unique()->join(",")->toArray();
return $data;
})->toArray();
}
)->toArray();
$result = [];
foreach ($arr as $person) {
foreach ($person as $key => $value) {
if ($key == 'id') {
$result[$person['id']][$key] = $value;
} else {
$result[$person['id']][$key][] = $value;
}
}
}
The magic really is in $result[$person['id']], which groups all items with the same id into the same result array very naturally. This also creates arrays for multiple values instead of merely concatenating the strings, which is a much saner data structure to work with. If you only want unique values, throw in an array_unique there. If you actually need to join the items with commas, use join(',', ..) at the end somewhere.
Check this below code,
function getMergerArray($arr) {
$newArr = array();
foreach ($arr as $key => $value) {
$id = $value['id'];
$name = $value['name'];
$age = $value['age'];
if (array_key_exists($id, $newArr)) {
if (!in_array($name, $newArr[$id]['name'])) {
$newArr[$id]['name'][] = $name;
}
if (!in_array($age, $newArr[$id]['age'])) {
$newArr[$id]['age'][] = $age;
}
continue;
}
$newArr[$id]['name'][] = $name;
$newArr[$id]['age'][] = $age;
}
foreach ($newArr as $key => $value) {
$newArr[$key] = array(
'id' => $key,
'name' => implode(', ', $value['name']),
'age' => implode(', ', $value['age']),
);
}
// echo '<pre>';
// print_r($newArr);
// echo '</pre>';
return $newArr;
}
Try this
function merge_multidimensional($arr) {
$out = array();
foreach ($arr as $key => $value){
$out[] = (object)array_merge((array)$arr2[$key], (array)$value);
}
return $out;
}
I have an array, looking like this:
[lund] => Array
(
[69] => foo
)
[berlin] => Array
(
[138] => foox2
)
[tokyo] => Array
(
[180] => foox2
[109] => Big entrance
[73] => foo
)
The thing is that there were duplicate keys, so I re-arranged them so I can search more specifically, I thought.
Previously I could just
$key = array_search('foo', $array);
to get the key but now I don't know how.
Question: I need key for value foo, from tokyo. How do I do that?
You can get all keys and value of foo by using this:
foreach ($array as $key => $value) {
$newArr[$key] = array_search('foo', $value);
}
print_r(array_filter($newArr));
Result is:
Array
(
[lund] => 69
[tokyo] => 109
)
If you don't mind about the hard code than you can use this:
array_search('foo', $array['tokyo']);
It just a simple example, you can modify it as per your requirement.
Try this
$a = array(
"land"=> array("69"=>"foo"),
"land1"=> array("138"=>"foo1"),
"land2"=> array('180' => 'foox2',
'109' => 'Big entrance',
'73' => 'foo'),
);
//print_r($a);
$reply = search_in_array($a, "foo");
print_r($reply);
function search_in_array($a, $search)
{
$result = array();
foreach($a as $key1 => $array ) {
foreach($array as $k => $value) {
if($value == "$search") {
array_push($result,"{$key1}=>{$k}");
breck;
}
}
}
return $result;
}
This function will return the key or null if the search value is not found.
function search($searchKey, $searchValue, $searchArr)
{
foreach ($searchArr as $key => $value) {
if ($key == $searchKey && in_array($searchValue, $value)) {
$results = array_search($searchValue, $value);
}
}
return isset($results) ? $results : null;
}
// var_dump(search('tokyo', 'foo', $array));
Since Question: I need key for value foo, from tokyo. How do i do that?
$key = array_search('foo', $array['tokyo']);
As a function:
function getKey($keyword, $city, $array) {
return array_search($keyword, $array[$city]);
}
// PS. Might be a good idea to wrap this array in an object and make getKey an object method.
If you want to get all cities (for example to loop through them):
$cities = array_keys($array);
I created solution using array iterator. Have a look on below solution:
$array = array(
'lund' => array
(
'69' => 'foo'
),
'berlin' => array
(
'138' => 'foox2'
),
'tokyo' => array
(
'180' => 'foox2',
'109' => 'Big entrance',
'73' => 'foo'
)
);
$main_key = 'tokyo'; //key of array
$search_value = 'foo'; //value which need to be search
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
foreach ($iterator as $key => $value) {
$keys = array();
if ($value == $search_value) {
$keys[] = $key;
for ($i = $iterator->getDepth() - 1; $i >= 0; $i--) {
$keys[] = $iterator->getSubIterator($i)->key();
}
$key_paths = array_reverse($keys);
if(in_array($main_key, $key_paths) !== false) {
echo "'{$key}' have '{$value}' value which traverse path is: " . implode(' -> ', $key_paths) . '<br>';
}
}
}
you can change value of $main_key and $serch_value according to your parameter. hope this will help you.
<?php
$lund = [
'69' => 'foo'
];
$berlin = [
'138' => 'foox2'
];
$tokyo = [
'180' => 'foox2',
'109' => 'Big entrance',
'73' => 'foo'
];
$array = [
$lund,
$berlin,
$tokyo
];
echo $array[2]['180']; // outputs 'foox2' from $tokyo array
?>
If you want to get key by specific key and value then your code should be:
function search_array($array, $key, $value)
{
if(is_array($array[$key])) {
return array_search($value, $array[$key]);
}
}
echo search_array($arr, 'tokyo', 'foo');
try this:
<?php
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 'On');
$array=array("lund" => array
(
69 => "foo"
),
"berlin" => array
(
138 => "foox2"
),
"tokyo" => array
(
180 => "foox2",
109 => "Big entrance",
73 => "foo"
));
function search($array, $arrkey1, $arrvalue2){
foreach($array as $arrkey=>$arrvalue){
if($arrkey == $arrkey1){
foreach($arrvalue as $arrkey=>$arrvalue){
if(preg_match("/$arrvalue/i",$arrvalue2))
return $arrkey;
}
}
}
}
$result=search($array, "tokyo", "foo"); //$array=array; tokyo="inside array to check"; foo="value" to check
echo $result;
You need to loop through array, since its 2 dimensional in this case. And then find corresponding value.
foreach($arr as $key1 => $key2 ) {
foreach($key2 as $k => $value) {
if($value == "foo") {
echo "{$k} => {$value}";
}
}
}
This example match key with $value, but you can do match with $k also, which in this case is $key2.
I want to dissect an array like this:
[
"ID",
"UUID",
"pushNotifications.sent",
"campaigns.boundDate",
"campaigns.endDate",
"campaigns.pushMessages.sentDate",
"pushNotifications.tapped"
]
To a format like this:
{
"ID" : 1,
"UUID" : 1,
"pushNotifications" :
{
"sent" : 1,
"tapped" : 1
},
"campaigns" :
{
"boundDate" : 1,
"endDate" : 1,
"pushMessages" :
{
"endDate" : 1
}
}
}
It would be great if I could just set a value on an associative array in a keypath-like manner:
//To achieve this:
$dissected['campaigns']['pushMessages']['sentDate'] = 1;
//By something like this:
$keypath = 'campaigns.pushMessages.sentDate';
$dissected{$keypath} = 1;
How to do this in PHP?
You can use :
$array = [
"ID",
"UUID",
"pushNotifications.sent",
"campaigns.boundDate",
"campaigns.endDate",
"campaigns.pushMessages.sentDate",
"pushNotifications.tapped"
];
// Build Data
$data = array();
foreach($array as $v) {
setValue($data, $v, 1);
}
// Get Value
echo getValue($data, "campaigns.pushMessages.sentDate"); // output 1
Function Used
function setValue(array &$data, $path, $value) {
$temp = &$data;
foreach(explode(".", $path) as $key) {
$temp = &$temp[$key];
}
$temp = $value;
}
function getValue($data, $path) {
$temp = $data;
foreach(explode(".", $path) as $ndx) {
$temp = isset($temp[$ndx]) ? $temp[$ndx] : null;
}
return $temp;
}
function keyset(&$arr, $keypath, $value = NULL)
{
$keys = explode('.', $keypath);
$current = &$arr;
while(count($keys))
{
$key = array_shift($keys);
if(!isset($current[$key]) && count($keys))
{
$current[$key] = array();
}
if(count($keys))
{
$current = &$current[$key];
}
}
$current[$key] = $value;
}
function keyget($arr, $keypath)
{
$keys = explode('.', $keypath);
$current = $arr;
foreach($keys as $key)
{
if(!isset($current[$key]))
{
return NULL;
}
$current = $current[$key];
}
return $current;
}
//Testing code:
$r = array();
header('content-type: text/plain; charset-utf8');
keyset($r, 'this.is.path', 39);
echo keyget($r, 'this.is.path');
var_dump($r);
It's a little rough, I can't guarantee it functions 100%.
Edit: At first you'd be tempted to try to use variable variables, but I've tried that in the past and it doesn't work, so you have to use functions to do it. This works with some limited tests. (And I just added a minor edit to remove an unnecessary array assignment.)
In the meanwhile, I came up with (another) solution:
private function setValueForKeyPath(&$array, $value, $keyPath)
{
$keys = explode(".", $keyPath, 2);
$firstKey = $keys[0];
$remainingKeys = (count($keys) == 2) ? $keys[1] : null;
$isLeaf = ($remainingKeys == null);
if ($isLeaf)
$array[$firstKey] = $value;
else
$this->setValueForKeyPath($array[$firstKey], $value, $remainingKeys);
}
Sorry for the "long" namings, I came from the Objective-C world. :)
So calling this on each keyPath, it actually gives me the output:
fields
Array
(
[0] => ID
[1] => UUID
[2] => pushNotifications.sent
[3] => campaigns.boundDate
[4] => campaigns.endDate
[5] => campaigns.pushMessages.endDate
[6] => pushNotifications.tapped
)
dissectedFields
Array
(
[ID] => 1
[UUID] => 1
[pushNotifications] => Array
(
[sent] => 1
[tapped] => 1
)
[campaigns] => Array
(
[boundDate] => 1
[endDate] => 1
[pushMessages] => Array
(
[endDate] => 1
)
)
)
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.