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;
}
Related
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;
}
I'm trying to figure out how to get data from the following data structure. I managed to group a flat array into the following array, but am finding it difficult to find the proper resources to explain how to get the data out. I'm looking to get the count of the items in each group. Then i'd like to print the ids from the inner array...
array (
'grinds' =>
array (
0 =>
array (
'id' => 16562,
'slug' => 'grinds',
),
1 =>
array (
'id' => 16561,
'slug' => 'grinds',
),
),
'online-grinds' =>
array (
0 =>
array (
'id' => 16566,
'slug' => 'online-grinds',
),
),
)
$my_array1 = array(
'grinds' =>
array(
0 =>
array(
'id' => 16562,
'slug' => 'grinds',
),
1 =>
array(
'id' => 16561,
'slug' => 'grinds',
),
),
'online-grinds' =>
array(
0 =>
array(
'id' => 16566,
'slug' => 'online-grinds',
),
),
);
get counts:
$counts = array();
foreach ($my_array1 as $key => $val) {
$counts[$key] = count($val);
}
var_dump($counts);
yields:
array(2) {
["grinds"]=>
int(2)
["online-grinds"]=>
int(1)
}
get inner ids:
$innerids = array();
foreach ($my_array1 as $key => $val) {
foreach ($val as $key2 => $val2) {
$innerids[] = $val2['id'];
}
}
var_dump($innerids);
yields:
array(3) {
[0]=>
int(16562)
[1]=>
int(16561)
[2]=>
int(16566)
}
You could use array_map and then for every item use array_column and specifing the field name and then use array_count_values to count the unique values.
Then combine those in an array and use the existing key again as the key for then new array.
$arrays = array_map(function($x) {
return [
array_count_values(array_column($x, 'id')),
array_count_values(array_column($x, 'slug'))
];
}, $arrays);
print_r($arrays);
Result
Array
(
[grinds] => Array
(
[0] => Array
(
[16562] => 1
[16561] => 1
)
[1] => Array
(
[grinds] => 2
)
)
[online-grinds] => Array
(
[0] => Array
(
[16566] => 1
)
[1] => Array
(
[online-grinds] => 1
)
)
)
Demo
This question already has answers here:
PHP merge two arrays on the same key AND value
(5 answers)
Closed 4 years ago.
Good evening, I have a little bit problem. I have two array. like
$firstArr = Array(
[0] => Array(
[customer_id] => 11,
[home_delivery] => no,
),
[1] => Array(
[customer_id] => 12,
[home_delivery] => no,
),
[2] => Array(
[customer_id] => 13,
[home_delivery] => no,
),
);
$secondArr = Array(
[0] => Array(
[customer_id] => 11,
[test] => no,
[is_active] => yes,
),
[1] => Array(
[customer_id] => 22,
[test] => no,
[is_active] => yes,
),
);
Now i want to get the result like first array's customer_id match with the second array customer_id. Id two array's customer id is same the the value of second array add with first array otherwise the value will be null. Hope guys you got my point what i want. The output which i want is like the below.
$getResult = Array(
[0] => Array(
[customer_id] => 11,
[home_delivery] => no,
[test] => no,
[is_active] => yes,
),
[1] => Array(
[customer_id] => 12,
[home_delivery] => no,
[test] => '',
[is_active] => '',
),
[2] => Array(
[customer_id] => 13,
[home_delivery] => no,
[test] => '',
[is_active] => '',
),
);
I have tried by this code, but it doesnt work. Please help me.
$mergedArray = array();
foreach ($firstArr as $index1 => $value1) {
foreach ($secondArr as $index2 => $value2) {
if ($array1[$index1]['customer_id'] == $array2[$index2]['customer_id']) {
$mergedArray[] = array_merge($firstArr[$index1], $secondArr[$index2]);
}
}
}
echo "<pre>"; print_r($mergedArray); echo "</pre>";
You can do this :
<?php
$results = [];
// Get all unique keys from both arrays
$keys = array_unique(array_merge(array_keys($firstArr[0]), array_keys($secondArr[0])));
// Make array of common customer_ids
foreach (array_merge($firstArr, $secondArr) as $record) {
$results[$record['customer_id']] = isset($results[$record['customer_id']]) ? array_merge($results[$record['customer_id']], $record) : $record;
}
// Fill keys which are not present with blank strings
foreach ($keys as $key) {
foreach ($results as $index => $result) {
if(!array_key_exists($key, $result)){
$results[$index][$key] = '';
}
}
}
print_r($results);
This is how I would do it:
$firstArr = array (
0 =>
array (
'customer_id' => 11,
'home_delivery' => 'no'
),
1 =>
array (
'customer_id' => 12,
'home_delivery' => 'no'
),
2 =>
array (
'customer_id' => 13,
'home_delivery' => 'no'
)
);
$secondArr = array (
0 =>
array (
'customer_id' => 11,
'test' => 'no',
'is_active' => 'yes'
),
1 =>
array (
'customer_id' => 22,
'test' => 'no',
'is_active' => 'yes'
)
);
$secondKey = array_column($secondArr,'customer_id');
foreach($firstArr as &$value){
$idx2 = array_search($value['customer_id'], $secondKey);
$value = array_merge($value, [
'test' => false !== $idx2 ? $secondArr[$idx2]['test'] : '',
'is_active' => false !== $idx2 ? $secondArr[$idx2]['is_active'] : '',
]);
}
print_r($firstArr);
Output:
Array
(
[0] => Array
(
[customer_id] => 11
[home_delivery] => no
[test] => no
[is_active] => yes
)
[1] => Array
(
[customer_id] => 12
[home_delivery] => no
[test] =>
[is_active] =>
)
[2] => Array
(
[customer_id] => 13
[home_delivery] => no
[test] =>
[is_active] =>
)
)
Sandbox
There are 2 "tricks" I use here, the first, and more important one, is array_column this picks just one column from an array, but the thing is the keys in the resulting array will match the original array. Which we can take advantage of.
The array we get from array column looks like this:
array (
0 => 11,
1 => 22
);
Because the keys match the original array we can use array_search (with the ID) to look up that key, which we can then use in the original array. This gives us an "easier" way to search the second array by flattening it out.
So for example when we look up $firstArr['customer_id'] = 11 in the above array we get the key 0 (which is not boolean false, see below). Then we can take that index and use it for the original array $secondArr and get the values from the other 2 columns.
-Note- that array search returns boolean false when it cant find the item, because PHP treats 0 and false the same we have to do a strict type check !== instead of just !=. Otherwise PHP will confuse the 0 index with being false, which is not something we want.
The second "trick" is use & in the foreach value, this is by reference which allows us to modify the array used in the loop, directly. This is optional as you could just as easily create a new array instead. But I thought I would show it as an option.
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).
How to extract unique values from this array.
I've tried another suggestion...
$input = array_map("unserialize", array_unique(array_map("serialize", $input)));
However because of the unix timestamp it wont work.
Im looking to extract only the second array index unique value and its array so should be left with..
// expected final
array(
2 => array(...),
3 => array(..)
)
$arr = array (
0 =>
array (
2 =>
array (
'date' => 1438173658,
'user' => 'admin',
),
),
1 =>
array (
2 =>
array (
'date' => 1438007944,
'user' => 'admin',
),
),
2 =>
array (
3 =>
array (
'date' => 1437746969,
'user' => 'supes',
),
)
)
Thanks.
Might be a simpler way, but here is one:
$result = array_intersect_key($arr,
array_unique(array_map(function($v) {
return current($v)['user'];
},
$arr)));