Sort php array based on current time - php

I am currently using the following json data. (The key is a time hh:mm)
"chart": {
"23:20": 11,
"23:30": 11,
"23:40": 11,
"23:50": 16,
"00:00": 16,
"00:10": 14,
"00:20": 11,
"00:30": 12,
"00:40": 14,
"00:50": 10,
"01:00": 8,
"01:10": 12,
"01:20": 15,
"01:30": 13,
"01:40": 11,
"01:50": 8,
"02:00": 8
}
https://pastebin.com/cp16Rr9w
I am then moving the data to a php array. I would like to sort the array, so it starts at the current server time and goes on from there.
At the moment i am using the following php (unsorted)
<?php
foreach ($data['chart'] as $key => $value){
echo 'Time: '.$key.'Data: '.$value;
}
?>

Try it:
$data = json_decode('{"chart": {
"23:20": 11,
"23:30": 11,
"23:40": 11,
"23:50": 16,
"00:00": 16,
"00:10": 14,
"00:20": 11,
"00:30": 12,
"00:40": 14,
"00:50": 10,
"01:00": 8,
"01:10": 12,
"01:20": 15,
"01:30": 13,
"01:40": 11,
"01:50": 8,
"02:00": 8
}}');
$data = (array) $data->chart;
function sort_time($a, $b) { return strtotime($a) > strtotime($b); }
uksort($data, 'sort_time' );
foreach ($data as $key => $value) {
echo "$key: $value\n";
}

The easiest approach perhaps would be to filter out all "too old" entries first with array_filter() and then sort the resulting array using ksort():
<?php
function getFilter($server_time) {
return function($item) use($server_time) {
return (strtotime($item) >= $server_time);
};
}
$data = '{"chart": {
"23:20": 11,"23:30": 11,"23:40": 11,"23:50": 16,"00:00": 16,
"00:10": 14,"00:20": 11,"00:30": 12,"00:40": 14,"00:50": 10,
"01:00": 8,"01:10": 12,"01:20": 15,"01:30": 13,"01:40": 11,
"01:50": 8,"02:00": 8
}}';
$json = json_decode($data, true);
$src = $json['chart'];
$server_time = strtotime("now");
$filtered = array_filter($src, getFilter($server_time), ARRAY_FILTER_USE_KEY);
ksort($filtered);
print_r($filtered);
Live test case: https://3v4l.org/M3RLm

function hsort($a, $b) // callback function for uksort function
{
return (floatval(str_replace(":", ".", $a)) - floatval(str_replace(":", ".", $b))) // convert each time to float value, like '01:56'-> "01.56", then compare values as float
}
$chart = array_flip($chart); // flip indexes with values to get ability to operate with indexes as array values (which are time in your array)
uksort($chart, "hsort"); // sort time values
$chart = array_flip($chart); // flip again to make time values as index again

Related

PHP array find two numbers are one after another

I have a sorted array with these stop_ids.
1,
6,
13,
18,
31,
I just want to find given first search value(6) is before the second given value(31). I tried something like this. That means the find order should be, first (6) then (13) not (13) first and (6) then.
foreach ($parent_array as $key => $value) {
$k = $key;
sort($routes); //another array with above values(stop_ids)
$st = 0;
foreach ($routes as $key => $value) {
if($st == 1){
unset($parent_array[$k]);
break;
}
elseif($value->stop_id == 31){
$st = 1;
continue;
}
}
}
return $parent_array;
I can provide two values. Here I used second value(31) only. Any help ???
Get array keys, under which is every number is located and compare this keys:
function firstNumberFirst($array, $first_number, $second_number)
{
return array_search($first_number, $array) < array_search($second_number, $array);
}
$a = [1, 6, 13, 18, 31];
var_dump(
firstNumberFirst($a, 6, 13),
firstNumberFirst($a, 6, 18),
firstNumberFirst($a, 13, 6)
);
If array is not zero-indexed - apply array_values first.

Need Three Highest Values (or more, if tied) of PHP Array and Their Location?

I have an array. I'd like to get the three highest values of the array, but also remember which part of the array it was in.
For example, if my array is [12,3,7,19,24], my result should be values 24,19,12, at locations 4, 0, 3.
How do I do that? The first part is easy. Getting the locations is difficult.
Secondly, I'd like to also use the top three OR top number after three, if some are tied. So, for example, if I have [18,18,17,17,4], I'd like to display 18, 18, 17, and 17, at location 0,1,2,3.
Does that make sense? Is there an easy way to do that?
Wouldn't you be there using asort()?
For example:
<?php
$list = [4,18,18,17,17];
// Sort maintaining indexes.
asort($list);
// Slice the first 3 elements from the array.
$top3 = array_slice($list, -3, null, true);
// Results in: [ 1 => 18, 2 => 18, 3 => 17 ]
Or you can use arsort
function getMyTop($list, $offset, $top) {
arsort($list);
return array_slice($list, $offset, $top, true);
}
$myTop = getMyTop($list, 0, 3);
$myNextTop = getMyTop($list, 3, 4);
This is what you need!
<?php
$array = array(12,3,7,19,24);
$array_processed = array();
$highest_index = 0;
while($highest_index < 3)
{
$max = max($array);
$index = array_search($max,$array);
$array_processed[$index] = $max;
unset($array[$index]);
$highest_index++;
}
print_r($array_processed);
?>
You will get Index as well as the value! You just have to define how many top values you want! Let me know if it's what you want!
function top_three_positions($array){
// Sort the array from max to min
arsort($array);
// Unset everything in sorted array after the first three elements
$count = 0;
foreach($array as $key => $ar){
if($count > 2){
unset($array[$key]);
}
$count++;
}
// Return array with top 3 values with their indexes preserved.
return $array;
}
You can use a loop to determine how many elements your top-three-with-ties will have, after applying arsort:
function getTop($arr, $num = 3) {
arsort($arr);
foreach(array_values($arr) as $i => $v) {
if ($i >= $num && $v !== $prev) return array_slice($arr, 0, $i, true);
$prev = $v;
}
return $arr;
}
// Sample input
$arr = [4,18,17,6,17,18,9];
$top = getTop($arr, 3);
print_r($top); // [5 => 18, 1 => 18, 4 => 17, 2 => 17]
try this:
public function getTopSortedThree(array $data, $n = 3, $asc = true)
{
if ($asc) {
uasort($data, function ($a, $b) { return $a>$b;});
} else {
uasort($data, function ($a, $b) { return $a<$b;});
}
$count = 0;
$result = [];
foreach ($data as $key => $value) {
$result[] = $data[$key];
$count++;
if ($count >= $n){
break;
}
}
return $result;
}
Send false for desc order and nothing for asc order
Send $n with number of top values you want.
This functionality doesn't losing keys.
This task merely calls for a descending sort, retention of the top three values, and in the case of values after the third-positioned value being equal to the third value, retain these as well.
After calling rsort(), call a for() loop starting from the fourth element ([3]). If the current value is not equal to the value in the third position, stop iterating, and isolate the elements from the front of the array to the previous iteration's index. Done.
p.s. If the input array has 3 or fewer elements, the for() loop is never entered and the whole (short) array avoids truncation after being sorted.
Code: (Demo)
$array = [18, 17, 4, 18, 17, 16, 17];
rsort($array);
for ($i = 3, $count = count($array); $i < $count; ++$i) {
if ($array[2] != $array[$i]) {
$array = array_slice($array, 0, $i);
break;
}
}
var_export($array);
Because the loop purely finds the appropriate finishing point of the array ($i), this could also be compacted to: (Demo)
rsort($array);
for ($i = 3, $count = count($array); $i < $count && $array[2] === $array[$i]; ++$i);
var_export(array_slice($array, 0, $i));
Or slightly reduced further to: (Demo)
rsort($array);
for ($i = 3; isset($array[2], $array[$i]) && $array[2] === $array[$i]; ++$i);
var_export(array_slice($array, 0, $i));
Output:
array (
0 => 18,
1 => 18,
2 => 17,
3 => 17,
4 => 17,
)

Delete elements from array in foreach in PHP (advanced)

Here is my problem:
I have an array with id's ($arr) which I'm slicing in groups of three. Next, I have an array with other id's ($otherIds) which I want to compare with main array ($arr), and if some of id's are identical - they should be deleted from rest of the $arr's chunks.
F.e. I have $arr = array(1, 2, 3, 4, 5, 6, 7, 8), and $otherIds = array(5, 7). I'm cutting $arr into the chunks of three elements, and then loop $arr in foreach and compare them to $otherIds, so in first iteration - code should see that $otherIds '5' and '7' exists in next chunks of $arr, and delete them.
My output should be:
1st iteration - array(1, 2, 3)
2nd iteration - array(4, 6) - 5 should be removed
3rd iteration - array(8) - 7 should be removed
$otherIds can be different in each iteration (they are taken from database), but to simplify it, I will use constant values.
Here is my code:
$arr = array(15, 10, 12, 17, 21, 13, 15, 25, 7, 18, 4, 1, 5, 2);
$chunks = array_chunk($arr, 3);
$ids = array();
foreach ($chunks as $k => $v) {
$otherIds = array(6, 7, 22, 31, 44, 9, 17);
$ids = $v;
foreach ($chunks as $key => $val) {
if ($key <= $k) continue;
foreach ($chunks[$key] as $g => $ch) {
foreach ($otherIds as $o) {
if ($ch['id'] == $o) {
$ids[] = $o;
unset($chunks[$key][$g]);
}
}
}
}
}
As You can see I use a lot of foreaches, but I cant see better solution...
Also, every next iteration of main foreach should be (as mentioned above) shortened by deleted elements from $otherIds - which I this code is NOT doing.
How to achieve it? Is there easier/better/more efficient solution?
I repeat: main goal is to check $otherIds in each iteration of main foreach, and delete same elements from $arr in other chunks.
When you modify an array you are iterating in a foreach loop, you mess up internal pointer in the array and things get confused.
Make a copy while picking up the triplets, do not do unset() nor modify the original array. Thanks to the copy-on-write feature in PHP, the copy will be fast and cost effective, even if the elements are big structures, not only numbers.
Try array_diff():
$arr = array(15, 10, 12, 17, 21, 13, 15, 25, 7, 18, 4, 1, 5, 2);
$chunks = array_chunk($arr, 3);
// Build the filtered list into $output
$output = array();
foreach ($chunks as $k => $v) {
$otherIds = array(6, 7, 22, 31, 44, 9, 17);
// array_diff() returns the list of values from $v that are not in $otherIds
$output[$k] = array_diff($v, $otherIds);
}
// Investigate the result
print_r($output);
Update
I re-read the question and I think I eventually understood the logic (which is not described in the sample data). On each iteration it gets a new set of IDs to ignore and removes them from all chunks, starting from the current chunk.
The updated code is:
$arr = array(15, 10, 12, 17, 21, 13, 15, 25, 7, 18, 4, 1, 5, 2);
$chunks = array_chunk($arr, 3);
// $chunks is numerically indexed; we can use for() to iterate it
// (avoid assigning to $v a value that is never used)
$count = count($chunks);
for ($k = 0; $k < $count; $k ++) {
$otherIds = array(6, 7, 22, 31, 44, 9, 17);
// $chunks is numerically indexed; start with key `$k` to iterate it
for ($key = $k; $key < $count; $key ++) {
// remove the values from $otherId present in the chunk
$chunks[$key] = array_diff($chunks[$key], $otherIds);
}
}

slice 2d array in php

Is there a way to slice 2d array when all column are all zeros? TIA
$cars = array(
array('Cars', 0, 18, 2, 4, 0, 3, 0, 8),
array('BMW', 0, 13, 2, 4, 0, 3, 0, 8),
array('Saab', 0, 29, 2, 4, 0, 3, 0, 8),
array('Land Rover', 0, 15, 2, 4, 0, 3, 0, 8),
);
echo '<table border="1">';
foreach ($cars as $car) {
echo '<tr>';
foreach ($car as $key) {
echo '<td>'.$key.'</td>';
}
echo '</tr>';
}
echo '</table>';
The following code will remove the columns if every value in the column has the value 0. If you had other plans such as slicing you still can use the code to help you identify what you want.
I do this before actually printing out the array as I do not simply know of a function to do this, so you'd have to create one.
The function array_column() is used to retrieve the columns and I compare it against array_intersect() that returns the rows with the same value and compare that against the amount of rows in your table.
$cols = count($cars[0]);
$rows = count($cars);
$filter = [0]; // add more unwanted values if you please
for($col=1; $col<$cols; $col++){ // skip index 0
if(count(array_intersect(array_column($cars, $col), $filter))) == $rows){
// We found a column "$col" where every value is "0".
foreach($cars as $k => $arr){
// Looping over the main array.
unset($arr[$col]); // unset the cloned array.
$cars[$k] = $arr; // update the original array with new value.
}
}
}
Now you can print your table with the same code you had.

PHP - checking for duplicate values in an array

The values in this array are inserted by pulling XML values (using the simplexml_load_file method) and a foreach loop.
$skuArray(2, 4, 3, 7, 7, 4, 1, 7, 9);
After populating the array, I then need to check to see if any duplicate values exist in the array (IE, 7 and 4 in this case). Product->sku contains the skuArray value (from an XML file) in the foreach loop below. The code below isn't working. Any advice? Thanks!
foreach($XMLproducts->product as $Product) {
if (in_array($Product->sku, $skuArray, > 1) {
// execute code
}
}
Use array_count_values() to get the number of times a value occurs and then check to see if it is more than one
$skuArray = array(2, 4, 3, 7, 7, 4, 1, 7, 9);
$dupes = array_count_values($skuArray);
foreach($XMLproducts->product as $Product) {
if ($dupes[$Product->sku] > 1) {
// execute code
}
}
If you need to remove the duplicates then you can use array_unique:
<?php
$input = array(4, 4, 3, 4, 3, 3);
$result = array_unique($input);
// $result = array(4, 3)
?>
If you need only check if there are duplicates then you can do it using array_count_values:
<?php
$input = array(2, 4, 3, 7, 7, 4, 1, 7, 9);
$counts = array_count_values($input);
$duplicates = array();
foreach($counts as $v => $count){
if($count > 1)
$duplicates[] = $v;
}
Then you will have an array $duplicates with the duplicated values.
Source: Php check duplicate values in an array
Your code has typo:
if (in_array($Product->sku, $skuArray, > 1) {
in_array expect the first parameter the needle, but you mentioned "Product->sku contains the skuArray value ", anyway, it should be like this:
if (in_array($Product->sku, $skuArray)) {

Categories