I have an associative array which has the following format:
array (
'Shopping and fashion' =>
array (
'childData' =>
array (
'Beauty' =>
array (
'childData' =>
array (
'Cosmetics' =>
array (
'id' => '6002839660079',
'name' => 'Cosmetics',
'parentName' => 'Beauty',
),
'Tattoos' =>
array (
'id' => '6003025268985',
'name' => 'Tattoos',
'parentName' => 'Beauty',
),),))))
I want to remove the keys from the array.
For this I am using :
array_values($my_data)
However, this only works for the topmost level of array, which in this case is "Shopping and fashion". It converts that to index 0.
How can I do the same for every array inside the index too?
EXPECTED OUTPUT:
array (
0 =>
array (
'childData' =>
array (
0 =>
array (
'childData' =>
array (
0 =>
array (
'id' => '6002839660079',
'name' => 'Cosmetics',
'parentName' => 'Beauty',
),
1 =>
array (
'id' => '6003025268985',
'name' => 'Tattoos',
'parentName' => 'Beauty',
),
),
'name' => 'Beauty',
'id' => '6002867432822',
'parentName' => 'Shopping and fashion',
),)))
The array I have has many different arrays on the parent level and many more array inside them so using for each is posing a problem as the number of "childData",i.e child arrays inside parent arrays are varying.
Could recursion be possible?
I don't know built-in function, but maybe this function would help you?
function array_values_recursive( $array ) {
$newArray = [];
foreach ( $array as $key => $value ) {
if ( is_array( $value ) ) {
$newArray[] = array_values_recursive( $value );
} else {
$newArray[$key] = $value;
}
}
return $newArray;
}
Related
I have this multidimensional PHP array:
array (
0 =>
array (
'name_lower' => 'apples',
'name' => 'Apples',
),
1 =>
array (
'name_lower' => 'pears',
'name' => 'Pears',
),
2 =>
array (
'name_lower' => 'avocados',
'name' => 'Avocados',
),
3 =>
array (
'name_lower' => 'bananas',
'name' => 'Bananas',
),
)
What I'm trying to manually reorder the arrays inside the multidimensional array and list them in exact the following order:
array (
0 =>
array (
'name_lower' => 'bananas',
'name' => 'Bananas',
),
1 =>
array (
'name_lower' => 'avocados',
'name' => 'Avocados',
),
2 =>
array (
'name_lower' => 'pears',
'name' => 'Pears',
),
3 =>
array (
'name_lower' => 'apples',
'name' => 'Apples',
),
)
It does not follow a pattern to automatically sort the arrays. It needs to be rearranged manually by name. Any ideas?
If you index the array on something unique and set an array with the sort order with those unique values, then you can map the sort order array and extract from the main array:
$sort = array('bananas', 'avocados', 'pears', 'apples');
$array = array_column($array, null, 'name_lower');
$array = array_map(function($v) use($array) { return $array[$v]; }, $sort);
I am trying to merge arrays with the same keys with different values, like below.
Input:
$array1 = array('1933' => array(
'nid' => '492811',
'title' => 'NEW TITLE',
'field_link_single_url' => 'abc',
'field_link_single_title' => 'test'
));
$array2 = array('1933' => array(
'nid' => '492811',
'title' => 'NEW TITLE',
'field_link_single_url' => 'xyz',
'field_link_single_title' => 'abcd'
));
Expected output to be:
Array
(
[nid] => 492811
[title] => NEW TITLE
[field_link_single_url] => [
[0] => 'abc',
[1] => 'xyz'
]
[field_link_single_title] => [
[0] => 'test',
[1] => 'abcd'
]
)
I have tried array_merge and array_merge_recursive but it does not work as expected.
Output of array_merge_recursive($array1[1933], $array2[1933]) it is creating duplicates keys having same value
Array
(
[nid] => Array
(
[0] => 492811
[1] => 492811
)
[title] => Array
(
[0] => Hal Louchheim
[1] => Hal Louchheim
)
[field_link_single_url] => Array
(
[0] => abc
[1] => xyz
)
[field_link_single_title] => Array
(
[0] => test
[1] => abcd
)
)
I made some assumption. If these assumptions are not valid, you should add some additional checks:
Both $array1 and $array2 are really arrays
Both $array1 and $array2 have the exact same keys
The values inside $array1 and $array2 are primitive types, not complex objects (the === operator would not work to compare objects or arrays)
function mergeArrayValues($array1, $array2) {
$output = [];
foreach($array1 as $key => $value) {
$output[$key] = $array1[$key] === $array2[$key]
? $array1[$key]
: [ $array1[$key], $array2[$key] ]
}
return $output;
}
mergeArrayValues($array1[1933], $array2[1933])
I have a multidimensional array and I would like to find an simple way to return the last occurrence of a key when "time_reported" is not NULL .
Example: for the array below the output should be the key n°2 cause it's the last array when a value is assigned.
array (
0 =>
array (
'point_name' => 'DOGAL',
'time_reported' => '2019-11-14 01:35:00',
),
1 =>
array (
'point_name' => '54/20',
'time_reported' => '2019-11-14 02:10:00',
),
2 =>
array (
'point_name' => '52/30',
'time_reported' => '2019-11-14 02:20:00',
),
3 =>
array (
'point_name' => '49/40',
'time_reported' => NULL,
),
4 =>
array (
'point_name' => '47/50',
'time_reported' => NULL,
),
5 =>
array (
'point_name' => 'PORTI',
'time_reported' => NULL,
),
)
I already had the idea to use a foreach loop to find the last occurrence but I don't know if it's the most efficient way to do that
Using foreach loop we can use array_reverse function so we can reverse the array, looping the last array to first. Then check if the key values is null or empty. You can see the result here.
<?php
$myarrays = array( array (
'point_name' => 'DOGAL',
'time_reported' => '2019-11-14 01:35:00',
),
array (
'point_name' => '54/20',
'time_reported' => '2019-11-14 02:10:00',
),
array (
'point_name' => '52/30',
'time_reported' => '2019-11-14 02:20:00',
),
array (
'point_name' => '49/40',
'time_reported' => NULL,
),
array (
'point_name' => '47/50',
'time_reported' => NULL,
),
array (
'point_name' => 'PORTI',
'time_reported' => NULL,
),
);
#echo "<pre>";
#print_r($myarrays);
foreach ( array_reverse($myarrays) as $array ) {
if($array['time_reported'] !== NULL){
echo $array['point_name']."\n";
echo $array['time_reported'];
break 1; // stop the loop
}
}
?>
If the array is in order, you can just traverse it until $item["time_reported"] is not null. This will get it done in O(N) in the worst case. If the array is not sorted, and you need the earliest / latest time, you will need to look at every element in the array for a best (and every) case of O(N).
$a = array(...);
for ($i = count($a) - 1; $i > 0 && $a[$i]["time_reported"] === null; $i--);
echo "Found at index {$i}\n";
Try this too:
function getLastNotNullValueInArray($array)
{
$reversed = array_reverse($array);
foreach($reversed as $arrValue)
{
if($arrValue)
return $arrValue;
}
return false;
}
Array (
[0] => Array (
[OrderProduct] => Array (
[pro_code] => B1
[totalQTY] => 4
)
)
[1] => Array (
[OrderProduct] => Array (
[pro_code] => B2
[totalQTY] => 4
)
)
[2] => Array (
[OrderProduct] => Array (
[pro_code] => B4
[totalQTY] => 4
)
)
)
Array (
[0] => Array (
[OrderProduct] => Array (
[pro_code] => B1
[totalDistSalesQTY] => 360
)
)
[1] => Array (
[OrderProduct] => Array (
[pro_code] => B2
[totalDistSalesQTY] => 600
)
)
[2] => Array (
[OrderProduct] => Array (
[pro_code] => B3
[totalDistSalesQTY] => 600
)
)
)
I would like to merge the two arrays above on the pro_code value. This is the expected result:
Array (
[0] => Array (
[OrderProduct] => Array (
[pro_code] => B1
[totalDistSalesQTY] => 360
[totalQTY] => 4
)
)
[1] => Array (
[OrderProduct] => Array (
[pro_code] => B2
[totalDistSalesQTY] => 600
[totalQTY] => 4
)
)
[2] => Array (
[OrderProduct] => Array (
[pro_code] => B3
[totalDistSalesQTY] => 600
)
)
[3] => Array (
[OrderProduct] => Array (
[pro_code] => B4
[totalQTY] => 4
)
)
)
I want to merge multiple array. Please help me to merge it properly. I applied many techniques to merge it. Still I could not find my way. Please help me with this issue.
So basically, what you have to do, is implement a merge algorithm on a sequence. It is one of the basic programming theses, so it shouldn't be too hard.
First, you have to sort the sequences in ascending order (the arrays in the example) by a unique, strictly sortable value (this is the pro_code in here).
Second, you need to iterate through both sequences at the same time.
If the current items unique key (pro_code) match, merge them and push to the result array, if not push the one with the lesser key to the result array. After pushing, increase the index of the pushed sequence by one.
After reaching the end of one of the sequences, push the rest to the result array.
And this is how it looks implemented in php:
<?php
// Compare func for usort
function compare($a, $b) {
return strcmp($a['OrderProduct']['pro_code'], $b['OrderProduct']['pro_code']);
}
// Sort array with usort
function sort_array(&$a) {
usort($a, 'compare');
}
// Print array
function print_a(&$a) {
print '<pre>';
print_r($a);
print '</pre>';
}
function list_merge(&$a, &$b) {
$resp = array();
$ia = 0;
$ib = 0;
while($ia < count($a) || $ib < count($b)) {
// Check if any of the arrays reached its end
// If not, check for merge
if(isset($a[$ia]) && isset($b[$ib])) {
// Product codes are matching,
// Push merged to $resp
if(strcmp($a[$ia]['OrderProduct']['pro_code'], $b[$ib]['OrderProduct']['pro_code']) == 0) {
$resp[] = array(
'OrderProduct' => array(
'pro_code' => $a[$ia]['OrderProduct']['pro_code'],
'totalQTY' => $a[$ia]['OrderProduct']['totalQTY'] + $b[$ib]['OrderProduct']['totalQTY'],
),
);
// If merge increment both
$ia++;
$ib++;
}
// Product code of element of $a is lesser,
// Push $a to $resp
elseif(strcmp($a[$ia]['OrderProduct']['pro_code'], $b[$ib]['OrderProduct']['pro_code']) < 0) {
$resp[] = array(
'OrderProduct' => array(
'pro_code' => $a[$ia]['OrderProduct']['pro_code'],
'totalQTY' => $a[$ia]['OrderProduct']['totalQTY'],
),
);
// Increment only pushed
$ia++;
}
// Product code of element of $b is lesser,
// Push $b to $resp
else {
$resp[] = array(
'OrderProduct' => array(
'pro_code' => $b[$ib]['OrderProduct']['pro_code'],
'totalQTY' => $b[$ib]['OrderProduct']['totalQTY'],
),
);
// Increment only pushed
$ib++;
}
}
// Else automatically push the existing array
// If $a exists
elseif(isset($a[$ia])) {
$resp[] = array(
'OrderProduct' => array(
'pro_code' => $a[$ia]['OrderProduct']['pro_code'],
'totalQTY' => $a[$ia]['OrderProduct']['totalQTY'],
),
);
// Increment only pushed
$ia++;
}
// Else automatically push the existing array
// If $b exists
else {
$resp[] = array(
'OrderProduct' => array(
'pro_code' => $b[$ib]['OrderProduct']['pro_code'],
'totalQTY' => $b[$ib]['OrderProduct']['totalQTY'],
),
);
// Increment only pushed
$ib++;
}
}
return $resp;
}
// Data structures
$array1 = array(
array(
'OrderProduct' => array(
'pro_code' => 'B1',
'totalQTY' => 4,
),
),
array(
'OrderProduct' => array(
'pro_code' => 'B2',
'totalQTY' => 4,
),
),
array(
'OrderProduct' => array(
'pro_code' => 'B4',
'totalQTY' => 4,
),
),
);
$array2 = array(
array(
'OrderProduct' => array(
'pro_code' => 'B1',
'totalQTY' => 360,
),
),
array(
'OrderProduct' => array(
'pro_code' => 'B2',
'totalQTY' => 600,
),
),
array(
'OrderProduct' => array(
'pro_code' => 'B3',
'totalQTY' => 600,
),
),
);
// Sort arrays by product code
sort_array($array1);
sort_array($array2);
// Merge arrays with list merge
$array3 = list_merge($array1, $array2);
// Print arrays for check
print_a($array1);
print_a($array2);
print_a($array3);
I hope, I could be of any help.
This is as condensed as I can make my method. It is effectively 3 simple steps with a custom function.
Code:
$QTY=[
["OrderProduct"=>
["pro_code"=>"B1","totalQTY"=>"4"]],
["OrderProduct"=>
["pro_code"=>"B2","totalQTY"=>"4"]],
["OrderProduct"=>
["pro_code"=>"B4","totalQTY"=>"4"]]
];
$DSQTY=[
["OrderProduct" =>
["pro_code"=>"B1","totalDistSalesQTY"=>"360"]],
["OrderProduct"=>
["pro_code"=>"B2","totalDistSalesQTY"=>"600"]],
["OrderProduct"=>
["pro_code"=>"B3","totalDistSalesQTY"=>"600"]]
];
function getDeepColumn($a,$c,$result=[]){
foreach(array_column(array_column($a,"OrderProduct"),$c,'pro_code') as $k=>$v){
$result[$k][$c]=$v;
}
return $result;
}
$merged=array_merge_recursive(getDeepColumn($QTY,'totalQTY'),getDeepColumn($DSQTY,'totalDistSalesQTY'));
ksort($merged); // make sure B4 is not before B3
foreach($merged as $k=>$a){
$result[]=["OrderProduct"=>array_merge(["pro_code"=>$k],$a)];
}
var_export($result);
Custom function explanation: getDeepColumn() uses array_column() with a nominated array and a nominated column name to extract the desired values from all OrderProduct subarrays. The column values are temporarily stored in an array of arrays called $result. $result's first level keys are pro_code values for future merging purposes. $result's subarrays consist of the nominated column's name (as key) and the nominated column's value (as values).
First, use array_merge_recursive() to blend together the desired deep column values.
Next, $merge is ksort()'ed (using the unique pro_code keys).
Finally, using foreach(), re-index all OrderProduct subarrays, and return the pro_code value to its rightful place inside the OrderProduct subarray.
Output:
array (
0 =>
array (
'OrderProduct' =>
array (
'pro_code' => 'B1',
'totalQTY' => '4',
'totalDistSalesQTY' => '360',
),
),
1 =>
array (
'OrderProduct' =>
array (
'pro_code' => 'B2',
'totalQTY' => '4',
'totalDistSalesQTY' => '600',
),
),
2 =>
array (
'OrderProduct' =>
array (
'pro_code' => 'B3',
'totalDistSalesQTY' => '600',
),
),
3 =>
array (
'OrderProduct' =>
array (
'pro_code' => 'B4',
'totalQTY' => '4',
),
),
)
This is pretty simple if you use the product code as a key in the result array.
// combine the two arrays together and iterate all their rows
foreach (array_merge($array1, $array2) as $row) {
// get the code
$code = $row['OrderProduct']['pro_code'];
// get the previous value for that code, or an empty array if there isnt' one
$prev = $result[$code]['OrderProduct'] ?? [];
// merge the previous value with the new value
$result[$code]['OrderProduct'] = array_merge($prev, $row['OrderProduct']);
}
You'll end up with product code keys in your result array, which is probably fine. If it's not fine, you can remove them with $result = array_values($result).
I have two arrays:
Array
(
[0] => Array
(
[id] => 1
[type] => field
[remote_name] => Title
[my_name] => title
[default_value] => http%3A%2F%2Ftest.com
)
[1] => Array
(
[id] => 2
[type] => field
[remote_name] => BookType
[my_name] => book-type
[default_value] =>
)
[2] => Array
(
[id] => 3
[type] => value
[remote_name] => dvd-disc
[my_name] => dvd
[default_value] =>
)
)
Array
(
[title] => Test
[book-type] => dvd
)
I need to take each key in the second array, match it with the my_name value in the first array and replace it with the corresponding remote_name value of the first array while preserving the value of the second array.
There's got to be some carrayzy function to help!
EDIT: There will also be a few cases that the value of the second array will need to be replaced by the value of the first array's remote_name where the value of the second array matches the value of the first array's my_name. How can I achieve this?
EG: book-type => dvd should turn into BookType => dvd-disc
Like so?:
$first = array(
array(
'id' => 1,
'type' => 'field',
'remote_name' => 'Title',
'my_name' => 'title',
'default_value' => 'http%3A%2F%2Ftest.com',
),
array(
'id' => 2,
'type' => 'field',
'remote_name' => 'BookType',
'my_name' => 'book-type',
'default_value' => '',
),
array(
'id' => 3,
'type' => 'value',
'remote_name' => 'dvd-disc',
'my_name' => 'dvd',
'default_value' => '',
),
);
$second = array(
'title' => 'Test',
'book-type' => 'dvd',
);
$map = array('fields' => array(), 'values' => array());
foreach ($first as $entry) {
switch ($entry['type']) {
case 'field':
$map['fields'][$entry['my_name']] = $entry['remote_name'];
break;
case 'value':
$map['values'][$entry['my_name']] = $entry['remote_name'];
break;
}
}
$new = array();
foreach ($second as $key => $val) {
$new[isset($map['fields'][$key]) ? $map['fields'][$key] : $key] = isset($map['values'][$val]) ? $map['values'][$val] : $val;
}
print_r($new);
Output:
Array
(
[Title] => Test
[BookType] => dvd-disc
)
Explanation:
The first loop collects the my_name/remote_name pairs for fields and values and makes them more accessible.
Like so:
Array
(
[fields] => Array
(
[title] => Title
[book-type] => BookType
)
[values] => Array
(
[dvd] => dvd-disc
)
)
The second loop will traverse $second and use the key/value pairs therein to populate $new. But while doing so will check for key/value duplicates in $map.
Keys or values not found in the map will be used as is.
foreach($arr1 as &$el) {
$el['remote_name'] = $arr2[$el['my_name']];
}
unset($el);
I am not aware of such a carrayzy function, but I know how you could do it:
//$array1 is first array, $array2 is second array
foreach($array1 as $key => $value){
if (isset($value['remote_name'], $value['my_name']) && $value['remote_name'] && $value['my_name']){
$my_name = $value['my_name'];
if (isset($array2[$my_name])) {
$remote_name = $value['remote_name'];
$array2[$remote_name] = $array2[$my_name];
//cleanup
unset($array2[$my_name]);
}
}
}