Recursively Reformat Prefixed Array [duplicate] - php

This question already has answers here:
How to access and manipulate multi-dimensional array by key names / path?
(10 answers)
Closed 6 years ago.
How can I convert a flat array into a nested array where the nested keys are prefixed with the same value. For example say I have the following array:
[
'name' => 'a',
'content' => 'b',
'author_fullName' => 'c',
'author_email' => 'd',
'author_role_name' => 'e'
]
Then the out of the array would be:
[
'name' => 'a',
'content' => 'b',
'author' => [
'fullName' => 'c',
'email' => 'd',
'role' => [
'name' => 'e'
]
]
]
Ideally I'd like a solution using the built in array functions as I prefer functional syntax rather than using for loops. I'd appreciate the help. Thanks

Try below code:
<?php
$a = [
'name' => 'a',
'content' => 'b',
'author_fullName' => 'c',
'author_email' => 'd',
'author_role_name' => 'e'
];
$finalArray =[];
array_walk($a, function(&$value, $key) use(&$finalArray) {
$indexes = explode('_',$key);
foreach ($indexes as $index){
$finalArray = &$finalArray[$index];
}
$finalArray = $value;
});
print_r($finalArray);

Another solution
$delimiter = '_';
$result = [];
foreach($array as $k => $v)
{
$split = explode($delimiter, $k, 2);//explode only as much as we need
if(count($split) > 1)
{
if(!isset($result[$split[0]]))
{
$result[$split[0]] = [];
}
//this assumes we're not interested in more than two depths
//in tandem with the explode limit
$result[$split[0]][$split[1]] = $v;
}
else
{
$result[$k] = $v;
}
}

Related

Check if the value of a key in one array is equal to the value of different key in another array

I have 2 multidimensional arrays and I want to get the 1st array where the value of [file] key in array 1 is equal to value of [folder_name] key in array 2
$arr1 = [
[
'is_dir' => '1',
'file' => 'hello member',
'file_lcase' => 'hello member',
'date' => '1550733362',
'size' => '0',
'permissions' => '',
'extension' => 'dir',
],
[
'is_dir' => '1',
'file' => 'in in test',
'file_lcase' => 'in in test',
'date' => '1550730845',
'size' => '0',
'permissions' => '',
'extension' => 'dir',
]
];
$arr2 = [
[
'dic_id' => '64',
'folder_name' => 'hello member',
'share_with' => '11',
],
[
'dic_id' => '65',
'folder_name' => 'hello inside',
'share_with' => '11',
],
[
'dic_id' => '66',
'folder_name' => 'in in test',
'share_with' => '11',
],
];
I have tried while looping 2 arrays and getting to one array but it is not success.
We can iterate both arrays inside each other to check until we have a match.
Please be aware that this shows only the first match. If you want to keep all matches you should use another helper array to store first array values that matches to second array.
foreach ($array1 as $key => $value) {
foreach ($array2 as $id => $item) {
if($value['file'] == $item['folder_name']){
// we have a match so we print out the first array element
print_r($array1[$key]);
break;
}
}
}
To avoid a double loop that gives a time complexity of O(n²), you could first create the set of "folder_name" values (as keys), and then use that to filter the first array. Both these operations have a time complexity of O(n) which is certainly more efficient for larger arrays:
$result = [];
$set = array_flip(array_column($arr2, "folder_name"));
foreach ($arr1 as $elem) {
if (isset($set[$elem["file"]])) $result[] = $elem;
}
$result will have the elements of $arr1 that meet the requirement.
$arr1 = array();
$arr2 = array();
$arr3 = array();
$arr1[] = array('is_dir'=>'1','file'=>'hello member','file_lcase'=>'hello member','date'=>'1550733362','size'=>'0','permissions'=>'','extension'=>'dir');
$arr1[] = array('is_dir'=>'1','file'=>'in in test','file_lcase'=>'in in test','date'=>'1550730845','size'=>'0','permissions'=>'','extension'=>'dir');
$arr2[] = array('dic_id'=>'64','folder_name'=>'hello member','share_with'=>'11');
$arr2[] = array('dic_id'=>'65','folder_name'=>'hello member','share_with'=>'11');
$arr2[] = array('dic_id'=>'66','folder_name'=>'in in test','share_with'=>'11');
foreach($arr1 as $a){
foreach($arr2 as $a2){
if($a['file'] == $a2['folder_name']){
$arr3[]=$a;
}
}
}
$arr3 = array_map("unserialize", array_unique(array_map("serialize", $arr3))); // remove duplicates
var_dump($arr3);
$arr3 contains the resultant array.

Replace array values by $replacements key/value map in PHP [duplicate]

This question already has answers here:
PHP - How to map elements of one array as keys to another array and return resulting values as an array?
(4 answers)
Closed 4 months ago.
I am having one (associative) data array $data with values, and another associative array $replacements.
I am looking for a short, easy and fast way to replace values in $data using the $replacements array.
The verbose way would be this:
function replace_array_values(array $data, array $replacements) {
$result = [];
foreach ($data as $k => $value) {
if (array_key_exists($value, $replacements)) {
$value = $replacements[$value];
}
$result[$k] = $value;
}
return $result;
}
Is there a native way to do this?
I know array_map(), but maybe there is something faster, without an extra function call per item?
Example:
See https://3v4l.org/g0sIJ
$data = array(
'a' => 'A',
'b' => 'B',
'c' => 'C',
'd' => 'D',
);
$replacements = array(
'B' => '(B)',
'D' => '(D)',
);
$expected_result = array(
'a' => 'A',
'b' => '(B)',
'c' => 'C',
'd' => '(D)',
);
assert($expected_result === replace_array_values($data, $replacements));
The simplest/least verbose way I can think of:
return array_map(function($value) use ($replacements) {
return array_key_exists($value, $replacements) ? $replacements[$value] : $value;
}, $data);
Using array_map is basically just looping over the array, which any other base function would also have to do anyway.
You can give a try to array_replace

Transpose and flatten two-dimensional indexed array where rows may not be of equal length

I would like to take an array like this and combine it into 1 single array.
array (size=2)
0 =>
array (size=10)
0 => string '1'
1 => string 'a'
2 => string '3'
3 => string 'c'
1 =>
array (size=5)
0 => string '2'
1 => string 'b'
However I want the array results to be interleaved.
So it would end up looking like
array
0 => '1'
1 => '2'
2 => 'a'
3 => 'b'
4 => '3'
5 => 'c'
I would like it so that it doesn't matter how many initial keys are passed in (this one has 2), it should work with 1, 2 or 5. Also, as you can see from my example the amount of elements most likely won't match.
Anyone know the best way to accomplish this?
$data = array(
0 => array(
0 => '1',
1 => 'a',
2 => '3',
3 => 'c',
),
1 => array(
0 => '2',
1 => 'b',
),
);
$newArray = array();
$mi = new MultipleIterator(MultipleIterator::MIT_NEED_ANY);
$mi->attachIterator(new ArrayIterator($data[0]));
$mi->attachIterator(new ArrayIterator($data[1]));
foreach($mi as $details) {
$newArray = array_merge(
$newArray,
array_filter($details)
);
}
var_dump($newArray);
I had fun with this... So if you like it use it!
$arr1 = [1,'a',3,'c'];
$arr2 = ['2','b'];
$finarry = arrayInterweave($arr1,$arr2);
print_r($finarry);
function arrayInterweave($arr1,$arr2){
$count1 = count($arr1);
$count2 = count($arr2);
$length = (($count1 >= $count2) ? $count1 : $count2);
$fin = array();
for($i = 0;$i<$length;$i++){
if(!empty($arr1[$i])){
$fin[] = $arr1[$i];
}
if(!empty($arr2[$i])){
$fin[] = $arr2[$i];
}
}
return $fin;
}
Tried to think of a fun solution:
$array = [
["a","b","c"],
["d","e"]
];
$result = [];
while($array) {
array_walk(
$array,
function(&$subarray, $key) use (&$array, &$result) {
$result[] = array_shift($subarray);
if(empty($subarray)) unset ($array[$key]);
}
);
}
var_dump($result);
It destroys the original array though.
After determining which row contains the most elements, you can loop through known indexes and push columns of data into the result array.
The following technique is safe to use with a variable number of rows.
Code: (Demo)
$maxCount = max(array_map('count', $array));
$result = [];
for ($i = 0; $i < $maxCount; ++$i) {
array_push($result, ...array_column($array, $i));
}
var_export($result);
Input/Output:
$array
$result
[['b', 'e', 'd', 's'], ['l', 'n']]
['b', 'l', 'e', 'n', 'd', 's']
['f', 'g', 'n', 's'], ['r', 'm'], ['a', 'e', 't']
['f', 'r', 'a', 'g', 'm', 'e', 'n', 't' 's']
The above technique is perfectly capable of accommodating 3 or more input arrays as well.
p.s. For anyone running into technical limitations because their php version, this will do the same:
$maxCount = max(array_map('count', $array));
$result = [];
for ($i = 0; $i < $maxCount; ++$i) {
foreach (array_column($array, $i) as $found) {
$result[] = $found;
}
}
...if your php version doesn't accommodate the above snippet, you really, really need to upgrade your php version (sorry, not sorry).
To avoid the counting to determine the longest subarray, you can instead transpose the data with nested loops then flatten that result structure. (Demo)
$result = [];
foreach ($array as $i => $row) {
foreach ($row as $k => $v) {
$result[$k][$i] = $v;
}
}
var_export(array_merge(...$result));

php - sort an array by key to match another array's order by key

I have two arrays, both have the same keys (different values) however array #2 is in a different order. I want to be able to resort the second array so it is in the same order as the first array.
Is there a function that can quickly do this?
I can't think of any off the top of my head, but if the keys are the same across both arrays then why not just loop over the first one and use its key order to create a new array using the the values from the 2nd one?
$arr1 = array(
'a' => '42',
'b' => '551',
'c' => '512',
'd' => 'gge',
) ;
$arr2 = array(
'd' => 'ordered',
'b' => 'is',
'c' => 'now',
'a' => 'this',
) ;
$arr2ordered = array() ;
foreach (array_keys($arr1) as $key) {
$arr2ordered[$key] = $arr2[$key] ;
}
You can use array_replace
$arr1 = [
'x' => '42',
'y' => '551',
'a' => '512',
'b' => 'gge',
];
$arr2 = [
'a' => 'ordered',
'x' => 'this',
'y' => 'is',
'b' => 'now',
];
$arr2 = array_replace($arr1, $arr2);
$arr2 is now
[
'x' => this,
'y' => is,
'a' => ordered,
'b' => now,
]
foreach(array_keys($array1) as $key)
{
$tempArray[$key] = $array2[$key];
}
$array2 = $tempArray;
I am not completely sure if this is what your after. anyways as long as the the array remains the same size, than this should work for you.
$gamey = array ("wow" => "World of Warcraft", "gw2" => "Guild Wars2", "wiz101" => "Wizard 101");
$gamex = array ("gw2" => "best game", "wiz101" => "WTF?", "wow" => "World greatest");
function match_arrayKeys ($x, $y)
{
$keys = array_keys ($x);
$values = array_values ($y);
for ($x = 0; $x < count ($keys); $x++)
{
$newarray [$keys[$x]] = $y[$keys[$x]];
}
return $newarray;
}
print_r (match_arrayKeys ($gamey, $gamex));
Output
[wow] => World greatest
[gw2] => best game
[wiz101] => WTF?
Try this
CODE
$fruits = array("d"=>"lemon", "a"=>"orange", "b"=>"banana", "c"=>"apple");
ksort($fruits);
foreach ($fruits as $key => $val) {
echo "$key = $val\n";
}
OUTPUT
a = orange
b = banana
c = apple
d = lemon
Check the php manual for ksort()

Compare values from three arrays PHP?

I have a maybe stupid question?
I have three arrays. And I want to get different values from the first and third array. I created the following code but the returned values are wrong.
function ec($str){
echo $str.'<br>';
}
$arr1 = array( array(
'letter' => 'A',
'number' => '1'
),
array(
'letter' => 'B',
'number' => '2'
),
array(
'letter' => 'C',
'number' => '3'
)
);
$arr2 = array( array(
'letter' => 'A',
'number' => '1'
),
array(
'letter' => 'B',
'number' => '2'
)
);
$arr3 = array( array(
'letter' => 'D',
'number' => '4'
),
array(
'letter' => 'E',
'number' => '5'
)
);
$mergeArr = array_merge($arr1,$arr3);
foreach ($mergeArr as $kMerge => $vMerge){
foreach ($arr2 as $val2){
if($val2['letter'] != $mergeArr[$kMerge]['letter']){
ec($mergeArr[$kMerge]['letter']);
}
}
}
The result of this code is:
A
B
C
C
D
D
E
E
The result I want:
C
D
E
Thanks in advance.
Based on the result you are looking for, this should do it:
$mergeArr = array_merge($arr1,$arr3);
$res = array_diff_assoc($mergeArr, $arr2);
var_dump($res);
See the snippet on codepad.
Try this instead of your foreach's:
$diff = array_diff($mergeArr, $arr2);
foreach( $diff as $d_k => $d_v ) {
ec($d_v['letter']);
}
If I understand what you are trying to do correctly, this function should do the job:
function find_unique_entries () {
$found = $repeated = array();
$args = func_get_args();
$key = array_shift($args);
foreach ($args as $arg) {
if (!is_array($arg)) return FALSE; // all arguments muct be arrays
foreach ($arg as $inner) {
if (!isset($inner[$key])) continue;
if (!in_array($inner[$key], $found)) {
$found[] = $inner[$key];
} else {
$repeated[] = $inner[$key];
}
}
}
return array_diff($found, $repeated);
}
Pass the key you are searching to the first arguments, then as many arrays as you like in the subsequent arguments. Returns an array of results or FALSE on error.
So your usage line would be:
$result = find_unique_entries('letter', $arr1, $arr2, $arr3);
See it working

Categories