Check PHP array for consecutive indexes - php

Sorry if the title of the question is unclear, I couldn't sum it up more precisely.
This is the issue:
To begin with, I have an array in this format:
Array (
[0] => 09:00
[1] => 10:00
[2] => 11:00
[3] => 12:00
[4] => 13:00
[5] => 14:00
[6] => 15:00
[7] => 16:00
[8] => 17:00
[9] => 18:00
)
Then some of the members are unset, so after that we're left with something like:
Array (
[0] => 09:00
[1] => 10:00
[6] => 15:00
[7] => 16:00
[8] => 17:00
[9] => 18:00
)
As you see, the array represents time slots. Now, what I need to do is eliminate all time slots shorter than 3 hours. So I need to go through the array and, wherever there are less than 3 members of the original array present, take them out too. So in the example above, since 09:00 and 10:00 are not followed by 11:00, I need to take them out and be left with:
Array (
[6] => 15:00
[7] => 16:00
[8] => 17:00
[9] => 18:00
)
How do I accomplish this? Logically, I think it might be easiest to check for 3 consecutive indexes, rather then checking the actual times but I'm open to any suggestions.

I've solved the problem on my own, and I made it generic so it would work for any duration, not just 3 hours.
$dur=3; //could be anything
foreach($work_times as $member){
$key=array_search($member,$work_times);
$a_ok=0;
for($options=0;$options<$dur;$options++){
$thisone=1;
for($try=$key-$options;$try<$key-$options+$dur;$try++){
if(!array_key_exists($try,$work_times))
$thisone=0;
}
if($thisone==1)
$a_ok=1;
}
if($a_ok==0)
unset($work_times[$key]);
}

$arr = array(
0 => '09:00',
1 => '10:00',
6 => '15:00',
7 => '16:00',
8 => '17:00',
9 => '18:00'
);
// for some testing
$arr += array(12 => '19:00', 13 => '20:00', 14 => '21:00');
$arr += array(16 => '22:00', 17 => '23:00');
$dontRemove = array();
foreach($arr as $key => $val) {
// if the next 2 keys are set
if (isset($arr[$key+1]) && isset($arr[$key+2])) {
$dontRemove[] = $key;
$dontRemove[] = $key+1;
$dontRemove[] = $key+2;
}
}
// combine and diff the keys to get the keys which should be actually removed
$remove = array_diff(array_keys($arr), array_unique($dontRemove));
foreach($remove as $key) {
unset($arr[$key]);
}
print_r($arr);

Try this:
<?php
function check() {
global $array;
$tmpArr = array_keys( $array );
$val1 = $tmpArr[0];
$val2 = $tmpArr[1];
$val3 = $tmpArr[2];
if( ( ++$val1 == $val2 ) && ( ++$val2 == $val3 ) ) {
// continuous
} else {
// not continuous, remove it
unset( $array[$tmpArr[0]] );
}
}
$array = array(
'0' => '09:00',
'1'=> '10:00',
'6' => '15:00',
'7'=> '16:00',
'8' => '17:00',
'9' => '18:00'
);
$total = count( $array );
$ctotal = 0;
while( $ctotal < $total ) {
if( count( $array ) <= 2 ) {
// this array has 2 elements left, which obviously
// nullifies the 3 continuous element check
$array = array();
break;
} else {
//check the array backwards
check();
$total--;
}
}
?>
Hope this helps

$a = Array(
0 => "09:00",
1 => "10:00",
6 => "15:00",
7 => "16:00",
8 => "17:00",
9 => "18:00",
11 => "20:00",
);
foreach ($a as $k => $v) {
// previous or next two time slots exist
$consecutive = (isset($a[$k-1]) or
(isset($a[$k+1]) and isset($a[$k+2])));
if (!$consecutive)
unset($a[$k]);
}

Related

How to convert multi-dimensional array of PHP data to an HTML table?

I'm trying to display a formatted HTML timetable using PHP.
I would like to output data from a multi-dimensional array to an HTML table that's formatted with a total of 8 columns (a column for each day Mon-Sun plus a column on the left showing the start times for each session).
The amount of rows depends on how many sessions there are for each day.
My solution works to a degree and you can see the output in the following image but you can also see that an extra row is generated for some reason. It's always just one extra row no matter the amount of sessions in a day.
The data is represented like this:
Array
(
[0] => Array
(
[0] => Array
(
[id] => 1
[name] => A Monday Session
[start_time] => 10:00
)
[1] => Array
(
[id] => 5
[name] => Another Monday Session
[start_time] => 11:00
)
[2] => Array
(
[id] => 6
[name] => Yet Another Monday Session
[start_time] => 12:00
)
)
[1] => Array
(
[0] => Array
(
)
)
[2] => Array
(
[0] => Array
(
[id] => 8
[name] => A Wednesday Session
[start_time] => 14:30
)
)
[3] => Array
(
[0] => Array
(
[id] => 3
[name] => A Thursday Session
[start_time] => 09:00
)
)
[4] => Array
(
[0] => Array
(
)
)
[5] => Array
(
[0] => Array
(
)
)
[6] => Array
(
[0] => Array
(
[id] => 4
[name] => A Sunday Session
[start_time] => 13:00
)
)
)
As you can see the main keys represent the days of the week. 0 = Monday, 1 = Tuesday etc.
Each day then has a list of sessions. In this example Monday has 3 sessions, and Wed,Thu,Sun each also have one.
Notice that they all have different starting times. The moment a session is introduced to the data with a duplicate start time, then extra rows are also created instead of sharing the same row. See output with the Thursday session changed to 10:00 to be the same as Monday:
And here is my buggy solution. I've marked with a comment the line where I'm going wrong.
// $sessionRows is the array of arrays containing the data above.
// Grabs array of session times from $sessionRows that has been sorted and duplicates removed.
// Current values: Array ( [0] => 09:00 [1] => 10:00 [2] => 11:00 [3] => 12:00 [4] => 13:00 [5] => 14:30 )
$sessionTimes = $this->getSessionTimes($days);
$numOfRows = count($sessionTimes);
$numOfCols = $dayIdx;
// Create grid with correct dimensions and rows represented by the session times
$grid = array();
for($i=0;$i<count($sessionTimes);$i++) {
$row = array();
for($j=0;$j<$numOfCols;$j++) {
$row[] = '<td></td>';
}
$grid[$sessionTimes[$i]] = $row;
}
// Populate grid with session info added to correct coordinates.
for($i=0;$i<$numOfCols;$i++) {
echo count($sessionRows[$i]);
for($j=0;$j<count($sessionRows);$j++) {
$grid[$sessionRows[$i][$j]['start_time']][$i] = $sessionRows[$i][$j];
}
}
$rows='';
$idx = 0;
foreach($grid as $rowArray) {
$rows .= '<tr>';
/*** This lines is the problem! It adds the session time as the first column. ***/
$rows .= '<td class="time-col">'.$sessionTimes[$idx].'</td>';
for($i=0;$i<count($rowArray);$i++) {
if(!empty($rowArray[$i]['name'])){
$rows .= '<td>'.$rowArray[$i]['name'].'<br>'.$rowArray[$i]['start_time'].'</td>';
} else {
$rows .= '<td> - </td>';
}
}
$rows .= '</tr>';
$idx++;
}
return $rows;
The problem was the $sessionTimes array was having duplicates removed by using the array_unique() function.
This function was preserving the index of the removed values. So the extra rows were being created without value.
Changing this to array_values(array_unique($array)) allowed regenerated keys and fixed the issue.
Thanks to anyone who had a look at it, wish I'd realised this earlier!
Here is an alternative solution that uses less loops.
What it does is it loops through the times, then loops through each day to determine whether the session start_time matches, if it does, add it to the output table.
<?php
$sessionTimes = ['09:00', '10:00', '11:00', '12:00', '13:00', '14:30'];
$schedule = [
[
[
'id' => 1,
'name' => 'A Monday Session',
'start_time' => '10:00'
],
[
'id' => 5,
'name' => 'Another Monday Session',
'start_time' => '11:00'
],
[
'id' => 6,
'name' => 'Yet Another Monday Session',
'start_time' => '12:00'
],
],
[
[]
],
[
[
'id' => 8,
'name' => 'A Wednesday Session',
'start_time' => '14:30'
]
],
[
[
'id' => 3,
'name' => 'A Thursday Session',
'start_time' => '09:00'
]
],
[
[]
],
[
[]
],
[
[
'id' => 4,
'name' => 'A Sunday Session',
'start_time' => '13:00'
]
]
];
$output = '<table><thead><tr><th></th><th>Monday</th><th>Tuesday</th><th>Wednesday</th><th>Thursday</th><th>Friday</th><th>Saturday</th><th>Sunday</th></thead><tbody>';
foreach ($sessionTimes as $sessionTime) {
$output .= '<tr><td>'.$sessionTime.'</td>';
$day = 0;
for ($i = 0; $i < count($schedule); $i++) {
if ($i == $day) {
$sessionAtTime = '<td>-</td>';
foreach ($schedule[$day] as $session) {
if (!empty($session) && $session['start_time'] == $sessionTime) {
$sessionAtTime = '<td><b>' . $session['name'] . '</b><br>Start: ' . $sessionTime.'</td>';
}
}
$output .= $sessionAtTime;
$day++;
}
}
$output .= '</tr>';
}
$output .= '</tbody></table>';
echo $output;

How to calculate two consecutive values in array

I am trying to loop through an array and calculate each value with next one. The data is like
[
['rate' => 1000, 'date' => '2017-07-10'],
['rate' => 2000, 'date' => '2017-08-14'],
['rate' => 3000, 'date' => '2017-08-18'],
['rate' => 1000, 'date' => '2017-07-23']
]
I have this [edited, following an example from another question in stackoverflow]:
#foreach ($users as $user)
#if ($user->admin_id == $active_user) // filtering users under this admin
#foreach ($userbillings as $userbilling)
#if($userbilling->user_id == $user->id) // filtering users
<?php
$count = count($userbilling->created_at);
$rates[] = $userbilling->rate;
$diff = 0;
for ($i=0; $i < $count; $i++) {
if (isset($rates[$i + 1])) {
$thisValue = $rates[$i];
$nextValue = $rates[$i + 1];
$diff = $nextValue - $thisValue;
}
}
echo $diff;
?>
#endif
#endforeach
#endif
#endforeach
This gives me result: 1000 2000 3000 1000 3000
What I want to achieve is to subtract first item from second, second item from third, third item from forth and so on, until it reaches to the last item. For last item, I want to keep the whole number.
I understand that I need to use array and loop here, and I have tried different ways for past 2 weeks, but cannot get even close.
Please suggest me how to make it work, or give me a guideline how I should proceed. I have searched plenty of questions here, but could not find anything right for my problem. If there is any, please suggest me the link.
You haven't specified your preferred output but assuming that you want to end up with an array result of the calculations for all pairs, plus the last element as-is, this should get you on the right track.
I would also second a comment above - do not do this sort of logic in a view as it belongs in a controller or somewhere like a service. Keep your views as simple as possible.
Not tested so please do so yourself:
<?php
$periods = [
['rate' => 1000, 'date' => '2017-07-14'],
['rate' => 3000, 'date' => '2017-08-18'],
['rate' => 2000, 'date' => '2017-08-10'],
['rate' => 3000, 'date' => '2017-08-15'],
['rate' => 1000, 'date' => '2017-08-23'],
];
$lastPeriod = count($periods) - 1;
$ratesForPeriods = [];
foreach ($periods as $index => $currentPeriod) {
if ($index === $lastPeriod) {
$ratesForPeriods[] = $currentPeriod; // add the last as-is
} else {
$nextPeriod = $periods[$index + 1];
$currentDate = new DateTime($currentPeriod['date']);
$interval = $currentDate->diff(new DateTime($nextPeriod['date']));
$ratesForPeriods[] = [
'from' => $currentPeriod['date'],
'to' => $nextPeriod['date'],
'rate' => $currentPeriod['rate'],
'days' => $interval->days,
'total' => $interval->days * $currentPeriod['rate'],
];
}
}
print_r($ratesForPeriods);
Yields:
Array
(
[0] => Array
(
[from] => 2017-07-14
[to] => 2017-08-18
[rate] => 1000
[days] => 35
[total] => 35000
)
[1] => Array
(
[from] => 2017-08-18
[to] => 2017-08-10
[rate] => 3000
[days] => 8
[total] => 24000
)
[2] => Array
(
[from] => 2017-08-10
[to] => 2017-08-15
[rate] => 2000
[days] => 5
[total] => 10000
)
[3] => Array
(
[from] => 2017-08-15
[to] => 2017-08-23
[rate] => 3000
[days] => 8
[total] => 24000
)
[4] => Array
(
[rate] => 1000
[date] => 2017-08-23
)
)
Hope this helps :)
Your question is not clear, but here is an example that might help you!
use array_slice() & array_sum()
$array = array( "0"=>1,"1"=>1,"2"=>5,"3"=>1,"4"=>1,"7"=>1,"8"=>3,"9"=>1);
$keys = array_keys($array);
$array = array_values($array);
$newArr = array();
foreach ($array as $key=>$val) {
$newArr[] = array_sum(array_slice($array, 0, $key+1));
}
$newArr = array_combine($keys, $newArr);
print '<pre>';
print_r($newArr);
print '</pre>';
Reference:
array_slice()
array_sum()
array_combine()
array_keys()
You can access the next item in foreach loop like following code :
foreach ($items as $key => $item)
{
echo !empty($items[$key+1]) ? ($items[$key+1]->rate - $item->rate) : $itema->rate;
}

PHP Multidimensional Array Sorting with Data and Time

I am working with any multidimensional array Sorting when I need to sort the array with values and the values should be sorted according tot he date and time. How could I do that.
For Some situation I cant do that through Query I need to Sort through PHP Sort but the predefined function dosent help me.
My Array to be sorted:
Array
(
[events] => Array
(
[0] => Array
(
[0] => 213532
[1] => 100% View
[2] => 12/11/2014 09:00
[3] => 12/11/2014 11:00
)
[1] => Array
(
[0] => 213533
[1] => test 80
[2] => 12/11/2014 06:00
[3] => 12/11/2014 08:00
)
[2] => Array
(
[0] => 213534
[1] => wf4
[2] => 12/12/2014 00:00
[3] => 12/12/2014 23:59
)
[3] => Array
(
[0] => 213535
[1] => Standaard:
[2] => 12/12/2014 10:00
[3] => 12/12/2014 12:00
)
)
)
Every Sub Array of [2] Value.
['events'][$i][2]
Should be sorted and rearranged. in the following way.
12/11/2014 06:00
12/11/2014 09:00
12/12/2014 00:00
12/12/2014 10:00
How can I do that any logical help will be useful.
#Mario is right that usort is what you probably want. You can also use strtotime to convert the string date to an integer, which is easy to compare. I wrote up a working example here. You'll see that I first print out the data (not sorted), then call usort with my custom sort function. When I print out the array again, it's now in order by date.
function compare($a, $b) {
$timeA = strtotime($a[2]);
$timeB = strtotime($b[2]);
if ($timeA < $timeB) {
return -1;
}
if ($timeA > $timeB) {
return 1;
}
return 0;
}
function printArrayContents($arr) {
for ($i = 0; $i < count($arr); $i++) {
echo $arr[$i][2] , "<BR>";
}
}
$events = array(
0 => array(
0 => 213532,
1 => '100% View',
2 => '12/11/2014 09:00',
3 => '12/11/2014 11:00'
),
1 => array(
0 => 213533,
1 => 'test 80',
2 => '12/11/2014 06:00',
3 => '12/11/2014 08:00'
),
2 => array(
0 => 213534,
1 => 'wf4',
2 => '12/12/2014 00:00',
3 => '12/12/2014 23:59'
),
3 => array(
0 => 213535,
1 => 'Standaard:',
2 => '12/12/2014 10:00',
3 => '12/12/2014 12:00'
)
);
echo "Unsorted:<BR>";
printArrayContents($events);
if (usort($events, "compare")) {
echo "Sorted:<BR>";
printArrayContents($events);
} else {
echo "Sort failed.<BR>";
}
Output:
Unsorted:
12/11/2014 09:00
12/11/2014 06:00
12/12/2014 00:00
12/12/2014 10:00
Sorted:
12/11/2014 06:00
12/11/2014 09:00
12/12/2014 00:00
12/12/2014 10:00
What you're looking for is usort(), which allows you to define your own callback/comparison function.
Essentially you'll want something like this:
function my_event_sorter($left, $right) {
if ($left[2] == $right[2])
return 0;
return strtotime($left[2]) < strtotime($right[2]) ? -1 : 1;
}
usort($events, 'my_event_sorter');
This comparison function will receive two parameters (the two elements to be compared) and it's supposed to return one of three integer values:
-1: The left value is smaller than the right one (i.e. order is fine).
0: Both values are identical (i.e. order is fine as well).
1: The right value is smaller than the left one (i.e. order has to be swapped).
if they are unique, you can use the datetime values as a key and then use ksort:
$newArray = array();
foreach($events as $event){
$newArray[$event[2]] = $event;
}
ksort($newArray);

php solution too huge if statement

Is there a way that I can approach this to some other solution?
I have 7 arrays (monday, tuesday, wednesday, thrusday, friday, saturday, sunday).
Each one of this arrays have arrays inside of them. and I need to check if all days have the same amount of data.
So im comparinng something like this:
if(count($monday) == count($tuesday)){
if(count($tuesday) == count($wednesday)){
if(count($wednesday) == count($thursday)){
if(count($thursday) == count($fruday)){
if(count($fruday) == count($saturday)){
if(count($saturday) == count($sunday)){
echo 'ok whole week is the same';
}
else{
//print sunday
//compare the rest which could print and keep comparing rest of the days
}
}
else{
//print saturday and comapre
}
}
else{
//print friday and compare
}
}
else{
//print thurdasy and compare
}
}
else{
//print wednesday and compare
}
}
else{
//print tuesday and compare
}
}
else{
//print monday
//compare rest of the days
}
As you can see it would become a huge if statement tree, I dont have that much of experience to know any other approach to this, but id you do, please help me!
thank you!
Use $diff = array_diff($monday,$tuesday,$wednesday, etc...);
$diff will contain the differences if there are any...
$bol = 0;
if(count($monday) == count($tuesday)){
$bol = $bol+1
} else {print $moday;}
//continue for all weeks
if ($bol ==6) {
echo 'ok whole week is the same';
}
How about this:
<?php
echo "<pre>";
$days = array('sunday' => array(1,2), 'saturday' => array(1,2,3), 'friday' => array(1,2,3,5), 'thursday' => array(1,2,3), 'wednesday' => array(1,2,3,4,5,6), 'tuesday' => array(1), 'monday' => array(1,2, 3,4,5,6,7,8));
//Create a count array
$count = array();
//populate count array
foreach ($days as $k => $v)
{
$count[$k] = count($v);
}
//reverse sort it
arsort($count);
//if both end of array elements are the same all are the same
if (reset ($count) == end($count))
{
echo 'ok whole week is the same';
} else {
foreach ($count as $d => $c)
{
echo $d . ": " . implode ( ", " , $days[$d] ) . "\n";
}
}
echo "</pre>";
?>
Initial array of days:
Array
(
[sunday] => Array
(
[0] => 1
[1] => 2
)
[saturday] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
[friday] => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 5
)
[thursday] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
[wednesday] => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
)
[tuesday] => Array
(
[0] => 1
)
[monday] => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
[6] => 7
[7] => 8
)
)
and Output:
monday: 1, 2, 3, 4, 5, 6, 7, 8
wednesday: 1, 2, 3, 4, 5, 6
friday: 1, 2, 3, 5
thursday: 1, 2, 3
saturday: 1, 2, 3
sunday: 1, 2
tuesday: 1
This solution uses the fact that the two comparison variables are quite predictable (ie. a single day is compared with the very next day).
All the daily arrays are placed into a single weekly array, which is then looped over. If there is a discrepancy, the contents of the last variable are displayed and the loop continues.
If there are no discrepancies then the success message is displayed.
<?php
$bIsCorrect = true;
$weeks_array = array($monday,$tuesday,$wednesday,$thursday,$friday,$saturday,$sunday);
//Loop through weeks starting from $monday and going only to $saturday
for($i=0,$max_count=6; $i<$max_count; $i++) {
if(count($weeks_array[$i]) != count($weeks_array[$i+1])) {
$bIsCorrect = false;
$array_text = var_export($weeks_array[$i+1], true);
echo "Discrepancy : <br> $array_text";
echo "<hr>";
}
}
if($bIsCorrect) {
echo "ok whole week is the same";
}

php time string array - delete values for specific period

[0] => 12:00:00
[1] => 12:15:00
[2] => 12:30:00
[3] => 12:45:00
[5] => 13:15:00
[6] => 13:30:00
[7] => 13:45:00
[8] => 14:00:00
[9] => 14:15:00
[10] => 14:30:00
How to delete the values from above array when my starttime is "12:30:00" and endtime is "14:00:00" ? The values should be deleted are 12:30:00, 12:45:00, 13:15:00, 13:45:00 and 14:00:00
For PHP >= 5.2.0, I would do something like this:
$time_array = array('0' => '11:00:00',
'1' => '12:00:00',
'2' => '13:00:00',
'3' => '14:00:00',
'4' => '15:00:00',
'5' => '16:00:00');
echo "\nBefore:\n";
print_r($time_array);
$start = new DateTime('12:30:00');
$end = new DateTime('14:00:00');
// Magic starts here
foreach ($time_array as $key => $value) {
$datetime = new DateTime($value);
if ($datetime >= $start and $datetime <= $end)
unset($time_array[$key]);
}
// Magic finished
echo "\nAfter:\n";
print_r($time_array);
Yes, it works.
You can use this if you dont need to preserve indexes
error_reporting(E_ALL);
$array = array(
0 => '12:00:00',
1 => '12:15:00',
2 => '12:30:00',
3 => '12:45:00',
5 => '13:15:00',
6 => '13:30:00',
7 => '13:45:00',
8 => '14:00:00',
9 => '14:15:00',
10 => '14:30:00',
);
$from = '12:30:00';
$to = '14:00:00';
$filtered = array();
foreach($array as $key => $value) {
if ($value < $from || $value > $to) {
$filtered[] = $value;
}
}
var_dump($filtered);
$var_arr = array();
$time_arr = array('12:00:00','12:15:00','12:30:00','12:45:00','13:15:00',
'13:30:00','13:45:00','14:00:00','14:15:00','14:30:00');
$start = strtotime('12:30:00');
$end = strtotime('14:00:00');
foreach($time_arr as $arr):
if(strtotime($arr)<$start || strtotime($arr)>$end):
$var_arr[] = $arr;
endif;
endforeach;
print_r($var_arr);

Categories