Alter array rows to be associative and append an additional associative element - php

I've created a method that allows me to assign keys to rows of values, and appends extra keys and values.
It adds all the new keys to a keys array, then adds all new values to the values array, and then combines all the keys and values.
How can I shrink it to make it smaller and more efficient?
$valores = array(array("1","1","1","1"),array("2","2","2","2"));//array of values
$keys = array('k1','k2','k3','k4'); //array of keys
$id = array('SpecialKey' => 'SpecialValue');//new array of items I want to add
function formatarArray($arrValores,$arrKeys,$identificadores){
foreach($identificadores as $k => $v){
array_push($arrKeys, $k);
}
foreach($arrValores as $i => $arrValor)
{
foreach($identificadores as $k => $v){
array_push($arrValor, $v);
}
$arrValores[$i] = array_combine($arrKeys, $arrValor);
}
var_export($arrValores);
}
Output:
array (
0 =>
array (
'k1' => '1',
'k2' => '1',
'k3' => '1',
'k4' => '1',
'SpecialKey' => 'SpecialValue',
),
1 =>
array (
'k1' => '2',
'k2' => '2',
'k3' => '2',
'k4' => '2',
'SpecialKey' => 'SpecialValue',
),
)
Viper-7(code debug):
http://viper-7.com/hbE1YF

function formatarArray($arrValores, $arrKeys, $identificadores)
{
foreach ($arrValores as &$arr)
$arr = array_merge(array_combine($arrKeys, $arr), $identificadores);
print_r($arrValores);
}
Could even be done in one line...
function formatarArray($arrValores, $arrKeys, $identificadores)
{
print_r(array_map(function ($arr) use ($arrKeys, $identificadores) { return array_merge(array_combine($arrKeys, $arr), $identificadores); }, $arrValores));
}

As a modernized form of #havenard's answer, I'd use PHP7.4's arrow function syntax to avoid the need for use() and I would use the array union operator (+) to avoid the iterated array_merge() calls. The array union operator is appropriate because it is adding an associative array to another array.
Code: (Demo)
var_export(
array_map(
fn($row) => array_combine($keys, $row) + $id,
$valores
)
);

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.

pass value of sub-array to key

I have this array :
$arr = array(0 => array('id' => "AMO"), 1 => array('id' => "PAT"));
And I would like to obtain this one :
array(
'AMO' => array(),
'PAT' => array()
)
How could I do this, in the shortest way possible ?
I can do it with an array_map, followed by an array_flip and next an array_walk .. but too long.
array_column to extract the keys and array_fill_keys to create the new array:
$arr = array(0 => array('id' => "AMO"), 1 => array('id' => "PAT"));
$res = array_fill_keys(array_column($arr, 'id'), []);
simply loop over array and make its id to new array key
$arr = array(0 => array('id' => "AMO"), 1 => array('id' => "PAT"));
foreach($arr as $value)
{
$new_arr[$value['id']] = array();
}
print_r($new_arr);
DEMO
I dont know what is the logic behind this, but you can try this one.
Here we are using array_combine, array_keys and array_fill
Try this code snippet here
$result= array_combine(
array_column($array,"id"),//getting column id
array_fill(0, count($array), array())//mapping that keys with empty array
);

How can I efficiently split an array into its associative key arrays?

How can I split a single array into it's sub-keys?
$arr = array(
0 => array(
'foo' => '1',
'bar' => 'A'
),
1 => array(
'foo' => '2',
'bar' => 'B'
),
2 => array(
'foo' => '3',
'bar' => 'C'
)
);
What is the most efficient way to return an array of foo and bar separately?
I need to get here:
$foo = array('1','2','3');
$bar = array('A','B','C');
I'm hoping there's a clever way to do this using array_map or something similar. Any ideas?
Or do I have to loop through and build each array that way? Something like:
foreach ($arr as $v) {
$foo[] = $v['foo'];
$bar[] = $v['bar'];
}
In a lucky coincidence, I needed to do almost the exact same thing earlier today. You can use array_map() in combination with array_shift():
$foo = array_map('array_shift', &$arr);
$bar = array_map('array_shift', &$arr);
Note that $arr is passed by reference! If you don't do that, then each time it would return the contents of $arr[<index>]['foo']. However, again because of the reference - you won't be able to reuse $arr, so if you need to do that - copy it first.
The downside is that your array keys need to be ordered in the same way as in your example, because array_shift() doesn't actually know what the key is. It will NOT work on the following array:
$arr = array(
0 => array(
'foo' => '1',
'bar' => 'A'
),
1 => array(
'bar' => 'B',
'foo' => '2'
),
2 => array(
'foo' => '3',
'bar' => 'C'
)
);
Update:
After reading the comments, it became evident that my solution triggers E_DEPRECATED warnings for call-time-pass-by-reference. Here's the suggested (and accepted as an answer) alternative by #Baba, which takes advantage of the two needed keys being the first and last elements of the second-dimension arrays:
$foo = array_map('array_shift', $arr);
$bar = array_map('array_pop', $arr);
$n = array();
foreach($arr as $key=>$val) {
foreach($val as $k=>$v) {
$n[$k][] = $v;
}
}
array_merge_recursive will combine scalar values with the same key into an array. e.g.:
array_merge_recursive(array('a',1), array('b',2)) === array(array('a','b'),array(1,2));
You can use this property to simply apply array_merge_recursive over each array in your array as a separate argument:
call_user_func_array('array_merge_recursive', $arr);
You will get this result:
array (
'foo' =>
array (
0 => '1',
1 => '2',
2 => '3',
),
'bar' =>
array (
0 => 'A',
1 => 'B',
2 => 'C',
),
)
It won't even be confused by keys in different order.
However, every merged value must be scalar! Arrays will be merged instead of added as a sub-array:
array_merge_recursive(array(1), array(array(2)) === array(array(1,2))
It does not produce array(array(1, array(2)))!

Combining two arrays by ID in PHP [duplicate]

This question already has answers here:
Merge two indexed arrays of indexed arrays based on first column value
(2 answers)
Closed 5 months ago.
I need to compare two 2D arrays in PHP. The arrays look like this:
Array one
ID Name
11 Aa
11 Ab
12 Bb
13 Cc
14 Dd
15 Ee
Array two
ID Content
11 Cat
13 Dog
14 Donkey
Now I'd need to combine these two into an array like this:
ID Name Conent
11 Aa Cat
11 Ab Cat
12 Bb
13 Cc Dog
14 Dd Donkey
15 Ee
How can I accomplish this? I have had no luck with array_merge() or $array3 = $array1 + $array2;
A quick way would be to iterate over the first array and append the value from the second:
$array1 = array('11' => 'Aa', '12' => 'Bb', '13' => 'Cc', '14' => 'Dd', '15' => 'Ee');
$array2 = array('11' => 'Cat', '13' => 'Dog', '14' => 'Donkey');
$combined = array();
foreach ($array1 as $key => $val) {
$combined[$key] = $val . (isset($array2[$key]) ? ' '.$array2[$key] : '');
}
This will loop through every key/value in $array1 and add it to the $combined array. If a value in $array2 exists with the same index, it will append it to that value from $array1, separated with a space.
UPDATE: I misread the format of the arrays (again). I assumed ID was the actual index in the array, but as the example array output has both Name and Content, I'm assuming ID is an actual index string value and not the index in the array itself. To stick with the loop scenario, you can iterate through the first array and have a nested loop iterate through the second:
$array1 = array(
array('ID' => '11', 'Name' => 'Aa'),
array('ID' => '12', 'Name' => 'Bb'),
array('ID' => '13', 'Name' => 'Cc'),
array('ID' => '14', 'Name' => 'Dd'),
array('ID' => '15', 'Name' => 'Ee'),
);
$array2 = array(
array('ID' => '11', 'Content' => 'Cat'),
array('ID' => '13', 'Content' => 'Dog'),
array('ID' => '14', 'Content' => 'Donkey')
);
$combined = array();
foreach ($array1 as $arr) {
$comb = array('ID' => $arr['ID'], 'Name' => $arr['Name'], 'Content' => '');
foreach ($array2 as $arr2) {
if ($arr2['ID'] == $arr['ID']) {
$comb['Content'] = $arr2['Content'];
break;
}
}
$combined[] = $comb;
}
This will add every value in $array1 to the combined array and if, and only if, a value in $array2 contains the same ID field will it add it's Content field to the array too. This can be extended to handle any number of fields as well, either by name, or by changing the inner-if block to have $comb += $arr2; instead (which should merge all non-existing indexes).
You will have to make your own function:
function putThemTogether($array1, $array2) {
$output = array();
foreach($array1 as $key => $value) {
if (!isset($output[$key]))
$output[$key] = array();
$output[$key][] = $value;
}
foreach($array2 as $key => $value) {
if (!isset($output[$key]))
$output[$key] = array();
$output[$key][] = $value;
}
return $output;
}
To make this better you could make it take an arbitrary number of arguments.
$result = array_map (
function ($item) { return is_array($item) ? implode(' ', $item) : $item; },
array_merge_recursive($array1, $array2);
);
Note, that both arrays require string keys
Another solution for this is to use array_search and array_column (since PHP 5.5.0).
foreach ($array1 as $key => $val) {
$found_key = array_search($val['ID'], array_column($array2, 'ID'));
if ($found_key !== false) { $array1[$key]['Content'] = $array2[$found_key]['Content']; }
}
Try this I hope It'll work
function merge_two_arrays($array1,$array2) {
$data = array();
$arrayAB = array_merge($array1,$array2);
foreach ($arrayAB as $value) {
// This assumes there is a field called "id"
$id = $value['id'];
if (!isset($data[$id])) {
$data[$id] = array();
}
$data[$id] = array_merge($data[$id],$value);
}
return $data;
}
$master_array = merge_two_arrays($array1,$array2);

How do I sort a multi-dimensional array by value?

I have an array as following and I want to order that array by the value of the key "attack". First keys of the arrays (15, 13, 18) are ID of some certain item from database, so I don't want these keys to be changed when the array is sorted. Any help would be greatly appreciated.
This is the array:
$data = array(
'15' => array(
'attack' => '45', 'defence' => '15', 'total' => '10'
),
'13' => array(
'attack' => '25', 'defence' => '15', 'total' => '10'
),
'18' => array(
'attack' => '35', 'defence' => '15', 'total' => '10'
)
);
Use uasort():
This function sorts an array such that array indices maintain their correlation with the array elements they are associated with, using a user-defined comparison function.
This is used mainly when sorting associative arrays where the actual element order is significant.
Example:
function cmp($a, $b) {
if ($a['attack'] == $b['attack']) {
return 0;
}
return ($a['attack'] < $b['attack']) ? -1 : 1;
}
uasort($data, 'cmp');
If the values are always strings, you can also use strcmp() in the cmp() function:
function cmp($a, $b) {
return strcmp($a['attack'], $b['attack']);
}
Update:
To sort in descending order you just have to change the return values:
return ($a['attack'] < $b['attack']) ? 1 : -1;
// ^----^
or to pick up #salathe's proposal:
return $b['attack'] - $a['attack'];
Simply use array_multisort
foreach ($data as $key => $row) {
$attack[$key] = $row['attack'];
}
// Sort the data with attack descending
array_multisort($attack, SORT_DESC, $data);
Hope this helps.
$result = [];
foreach ($data as $key => $value) {
$result[$key] = $value;
asort($result[$key]);
}
print_r($result);
Hope this helps !!!

Categories