I'm trying to reimplement python slice notation in another language (php) and looking for a snippet (in any language or pseudocode) that would mimic the python logic. That is, given a list and a triple (start, stop, step) or a part thereof, determine correct values or defaults for all parameters and return a slice as a new list.
I tried looking into the source. That code is far beyond my c skills, but I can't help but agree with the comment saying:
/* this is harder to get right than you might think */
Also, if something like this is already done, pointers will be greatly appreciated.
This is my test bench (make sure your code passes before posting):
#place your code below
code = """
def mySlice(L, start=None, stop=None, step=None):
or
<?php function mySlice($L, $start=NULL, $stop=NULL, $step=NULL) ...
or
function mySlice(L, start, stop, step) ...
"""
import itertools
L = [0,1,2,3,4,5,6,7,8,9]
if code.strip().startswith('<?php'):
mode = 'php'
if code.strip().startswith('def'):
mode = 'python'
if code.strip().startswith('function'):
mode = 'js'
if mode == 'php':
var, none = '$L', 'NULL'
print code, '\n'
print '$L=array(%s);' % ','.join(str(x) for x in L)
print "function _c($s,$a,$e){if($a!==$e)echo $s,' should be [',implode(',',$e),'] got [',implode(',',$a),']',PHP_EOL;}"
if mode == 'python':
var, none = 'L', 'None'
print code, '\n'
print 'L=%r' % L
print "def _c(s,a,e):\n\tif a!=e:\n\t\tprint s,'should be',e,'got',a"
if mode == 'js':
var, none = 'L', 'undefined'
print code, '\n'
print 'L=%r' % L
print "function _c(s,a,e){if(a.join()!==e.join())console.log(s+' should be ['+e.join()+'] got ['+a.join()+']');}"
print
n = len(L) + 3
start = range(-n, n) + [None, 100, -100]
stop = range(-n, n) + [None, 100, -100]
step = range(-n, n) + [100, -100]
for q in itertools.product(start, stop, step):
if not q[2]: q = q[:-1]
actual = 'mySlice(%s,%s)' % (var, ','.join(none if x is None else str(x) for x in q))
slice_ = 'L[%s]' % ':'.join('' if x is None else str(x) for x in q)
expect = eval(slice_)
if mode == 'php':
expect = 'array(%s)' % ','.join(str(x) for x in expect)
print "_c(%r,%s,%s);" % (slice_, actual, expect)
if mode == 'python':
print "_c(%r,%s,%s);" % (slice_, actual, expect)
if mode == 'js':
print "_c(%r,%s,%s);" % (slice_, actual, expect)
how to use it:
save into a file (test.py)
place your python, php or javascript code between """s
run python test.py | python or python test.py | php or python test.py | node
Here's a straight port of the C code:
def adjust_endpoint(length, endpoint, step):
if endpoint < 0:
endpoint += length
if endpoint < 0:
endpoint = -1 if step < 0 else 0
elif endpoint >= length:
endpoint = length - 1 if step < 0 else length
return endpoint
def adjust_slice(length, start, stop, step):
if step is None:
step = 1
elif step == 0:
raise ValueError("step cannot be 0")
if start is None:
start = length - 1 if step < 0 else 0
else:
start = adjust_endpoint(length, start, step)
if stop is None:
stop = -1 if step < 0 else length
else:
stop = adjust_endpoint(length, stop, step)
return start, stop, step
def slice_indices(length, start, stop, step):
start, stop, step = adjust_slice(length, start, stop, step)
i = start
while (i > stop) if step < 0 else (i < stop):
yield i
i += step
def mySlice(L, start=None, stop=None, step=None):
return [L[i] for i in slice_indices(len(L), start, stop, step)]
This is what I came up with (python)
def mySlice(L, start=None, stop=None, step=None):
answer = []
if not start:
start = 0
if start < 0:
start += len(L)
if not stop:
stop = len(L)
if stop < 0:
stop += len(L)
if not step:
step = 1
if stop == start or (stop<=start and step>0) or (stop>=start and step<0):
return []
i = start
while i != stop:
try:
answer.append(L[i])
i += step
except:
break
return answer
Seems to work - let me know what you think
Hope it helps
This is a solution I came up with in C# .NET, maybe not the prettiest, but it works.
private object[] Slice(object[] list, int start = 0, int stop = 0, int step = 0)
{
List<object> result = new List<object>();
if (step == 0) step = 1;
if (start < 0)
{
for (int i = list.Length + start; i < list.Length - (list.Length + start); i++)
{
result.Add(list[i]);
}
}
if (start >= 0 && stop == 0) stop = list.Length - (start >= 0 ? start : 0);
else if (start >= 0 && stop < 0) stop = list.Length + stop;
int loopStart = (start < 0 ? 0 : start);
int loopEnd = (start > 0 ? start + stop : stop);
if (step > 0)
{
for (int i = loopStart; i < loopEnd; i += step)
result.Add(list[i]);
}
else if (step < 0)
{
for (int i = loopEnd - 1; i >= loopStart; i += step)
result.Add(list[i]);
}
return result.ToArray();
}
I've written a PHP port based on the C code, optimized for step sizes -1 and 1:
function get_indices($length, $step, &$start, &$end, &$size)
{
if (is_null($start)) {
$start = $step < 0 ? $length - 1 : 0;
} else {
if ($start < 0) {
$start += $length;
if ($start < 0) {
$start = $step < 0 ? -1 : 0;
}
} elseif ($start >= $length) {
$start = $step < 0 ? $length - 1 : $length;
}
}
if (is_null($end)) {
$end = $step < 0 ? -1 : $length;
} else {
if ($end < 0) {
$end += $length;
if ($end < 0) {
$end = $step < 0 ? - 1 : 0;
}
} elseif ($end >= $length) {
$end = $step < 0 ? $length - 1 : $length;
}
}
if (($step < 0 && $end >= $start) || ($step > 0 && $start >= $end)) {
$size = 0;
} elseif ($step < 0) {
$size = ($end - $start + 1) / $step + 1;
} else {
$size = ($end - $start - 1) / $step + 1;
}
}
function mySlice($L, $start = NULL, $end = NULL, $step = 1)
{
if (!$step) {
return false; // could throw exception too
}
$length = count($L);
get_indices($length, $step, $start, $end, $size);
// optimize default step
if ($step == 1) {
// apply native array_slice()
return array_slice($L, $start, $size);
} elseif ($step == -1) {
// negative step needs an array reversal first
// with range translation
return array_slice(array_reverse($L), $length - $start - 1, $size);
} else {
// standard fallback
$r = array();
for ($i = $start; $step < 0 ? $i > $end : $i < $end; $i += $step) {
$r[] = $L[$i];
}
return $r;
}
}
This is based on #ecatmur's Python code ported again to PHP.
<?php
function adjust_endpoint($length, $endpoint, $step) {
if ($endpoint < 0) {
$endpoint += $length;
if ($endpoint < 0) {
$endpoint = $step < 0 ? -1 : 0;
}
}
elseif ($endpoint >= $length) {
$endpoint = $step < 0 ? $length - 1 : $length;
}
return $endpoint;
}
function mySlice($L, $start = null, $stop = null, $step = null) {
$sliced = array();
$length = count($L);
// adjust_slice()
if ($step === null) {
$step = 1;
}
elseif ($step == 0) {
throw new Exception('step cannot be 0');
}
if ($start === null) {
$start = $step < 0 ? $length - 1 : 0;
}
else {
$start = adjust_endpoint($length, $start, $step);
}
if ($stop === null) {
$stop = $step < 0 ? -1 : $length;
}
else {
$stop = adjust_endpoint($length, $stop, $step);
}
// slice_indices()
$i = $start;
$result = array();
while ($step < 0 ? ($i > $stop) : ($i < $stop)) {
$sliced []= $L[$i];
$i += $step;
}
return $sliced;
}
I can't say there's no bug in the codes, but it had past your test program :)
def mySlice(L, start=None, stop=None, step=None):
ret = []
le = len(L)
if step is None: step = 1
if step > 0: #this situation might be easier
if start is None:
start = 0
else:
if start < 0: start += le
if start < 0: start = 0
if start > le: start = le
if stop is None:
stop = le
else:
if stop < 0: stop += le
if stop < 0: stop = 0
if stop > le: stop = le
else:
if start is None:
start = le-1
else:
if start < 0: start += le
if start < 0: start = -1
if start >= le: start = le-1
if stop is None:
stop = -1 #stop is not 0 because we need L[0]
else:
if stop < 0: stop += le
if stop < 0: stop = -1
if stop >= le: stop = le
#(stop-start)*step>0 to make sure 2 things:
#1: step != 0
#2: iteration will end
while start != stop and (stop-start)*step > 0 and start >=0 and start < le:
ret.append( L[start] )
start += step
return ret
Related
I'm trying to translate this algorithm from C language to PHP (for study)
This is an example of a perceptron. I copied the example written in c and I'm trying to translate it into PHP. Currently I wrote this code, what am I wrong? As output I only know 101 iterations with result always 1.
This is the C program:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define LEARNING_RATE 0.1
#define MAX_ITERATION 100
float randomFloat()
{
return (float)rand() / (float)RAND_MAX;
}
int calculateOutput(float weights[], float x, float y)
{
float sum = x * weights[0] + y * weights[1] + weights[2];
return (sum >= 0) ? 1 : -1;
}
int main(int argc, char *argv[])
{
srand(time(NULL));
float x[208], y[208], weights[3], localError, globalError;
int outputs[208], patternCount, i, p, iteration, output;
FILE *fp;
if ((fp = fopen("test1.txt", "r")) == NULL) {
printf("Cannot open file.\n");
exit(1);
}
i = 0;
while (fscanf(fp, "%f %f %d", &x[i], &y[i], &outputs[i]) != EOF) {
if (outputs[i] == 0) {
outputs[i] = -1;
}
i++;
}
patternCount = i;
weights[0] = randomFloat();
weights[1] = randomFloat();
weights[2] = randomFloat();
iteration = 0;
do {
iteration++;
globalError = 0;
for (p = 0; p < patternCount; p++) {
output = calculateOutput(weights, x[p], y[p]);
localError = outputs[p] - output;
weights[0] += LEARNING_RATE * localError * x[p];
weights[1] += LEARNING_RATE * localError * y[p];
weights[2] += LEARNING_RATE * localError;
globalError += (localError*localError);
}
/* Root Mean Squared Error */
printf("Iteration %d : RMSE = %.4f\n", iteration,
sqrt(globalError/patternCount));
} while (globalError != 0 && iteration<=MAX_ITERATION);
printf("\nDecision boundary (line) equation: %.2f*x + %.2f*y + %.2f = 0\n",
weights[0], weights[1], weights[2]);
return 0;
}
and this is the code that I wrote
<?php
define("LEARNING_RATE", 0.1);
define("MAX_ITERATION", 100);
function randomFloat(){ return (float) mt_rand() / mt_getrandmax(); }
function calculateOutput($weights, $x, $y){
$sum = (float) $x * $weights[0] + $y * $weights[1] + $weights[2];
return ($sum >= 0) ? 1 : -1;
}
srand(time());
$i = 0;
$ars = explode("\n",file_get_contents('https://raw.githubusercontent.com/RichardKnop/ansi-c-perceptron/master/test1.txt'));
foreach($ars as $ar){
$temp = explode("\t", $ar);
$x[$i] = (float) $temp[0];
$y[$i] = (float) $temp[1];
$output[$i] = (int) $temp[2];
if($output[$i] == 0)
$output[$i] = -1;
$i++;
}
$patternCount = $i;
$weights[0] = randomFloat();
$weights[1] = randomFloat();
$weights[2] = randomFloat();
$iteration = 0;
do{
$iteration++;
$globalError = 0;
for ($p = 0; $p < $patternCount; $p++) {
$output = calculateOutput($weights, $x[$p], $y[$p]);
$localError = $outputs[$p] - $output;
$weights[0] += LEARNING_RATE * $localError * $x[$p];
$weights[1] += LEARNING_RATE * $localError * $y[$p];
$weights[2] += LEARNING_RATE * $localError;
$globalError += ($localError*$localError);
}
$r .= "Iteration $iteration : RMSE = " .
sqrt($globalError/$patternCount)."<br>";
}while($globalError != 0 && $iteration<=MAX_ITERATION);
echo $r;
echo "<br><hr><br>";
echo "Decision boundary (line) equation: ".$weights[0]."*x + ".$weights[1]."*y + ".$weights[2]." = 0<br>";
it's practically identical, but why does it not work?
$ars = explode("\n",file_get_contents('…'));
Since the file ends with a \n, this yields an empty string as the last array value, which disrupts the foreach($ars as $ar) loop. To read the file into an array, simply use:
$ars = file('…');
In the foreach($ars as $ar) loop, you used the wrong name $output[$i] instead of $outputs[$i].
$r .= "Iteration $iteration : RMSE = " .
sqrt($globalError/$patternCount)."<br>";
}while($globalError != 0 && $iteration<=MAX_ITERATION);
echo $r;
You didn't initialize $r. Instead of the above, you can use:
echo "Iteration $iteration : RMSE = " .
sqrt($globalError/$patternCount)."<br>";
} while ($globalError != 0 && $iteration<=MAX_ITERATION);
I'm using MKMapView and I send my php program the visible region (center lat, center lon, span lat, span lon). I need to determine if a coordinate is inside that region using php. I'm hoping there's a standard formula somewhere, but I haven't found one. I'll keep trying to come up with a formula, but it's surprisingly complicated (hopefully not as much as the haversine, which I don't believe I could have figured out myself).
lets try this logic
$topRightLongitude = $centerLongitude + $spanLongitude/2;
if($topRightLongitude > 180 and ($pointLongitude < 0))
$topRightLongitude = $topRightLongitude - 360; // (180*2) - positive becomes negative
$bottomLeftLongitude = $centerLongitude - $spanLongitude/2;
if($bottomLeftLongitude< -180 and ($pointLongitude > 0))
$bottomLeftLongitude= 360 + $bottomLeftLongitude; // now is negative and will become positive
$topRightLatitude = $centerLatitude + $spanLatitude/2;
if($topRightLatitude > 90 and ($pointLatitude < 0))
$topRightLatitude = $topRightLatitude - 180; // (90*2) - positive becomes negative
$bottomLeftLatitude = $centerLatitude - $spanLatitude/2;
if($bottomLeftLatitude< -90 and ($pointLatitude > 0))
$bottomLeftLatitude= 180 + $bottomLeftLongitude; // now is negative and will become positive
if you have
$centerLongitude = 179;
$spanLongitude = 20;
$pointLongitude = -179;
results
$topRightLongitude = -171;
$bottomLeftLongitude = 169;
so your point is in if you test like this:
if($pointLongitude < $topRightLongitude &&
$pointLongitude > $bottomLeftLongitude &&
$pointLatitude < $topRightLatitude &&
$pointLatitude > $bottomLeftLatitude){
echo 'in';
}else{
echo 'out';
}
My Solution
$top = $c_lat + ($d_lat / 2.0);
$bottom = $c_lat - ($d_lat / 2.0);
$left = $c_lon - ($d_lon / 2.0);
$right = $c_lon + ($d_lon / 2.0);
if($left < -180)
{
$second_left = $left + 360.0;
$second_right = 180.0;
$left = -180;
}
elseif($right > 180)
{
$second_right = $right - 360.0;
$second_left = -180.0;
$right = 180.0;
}
$inside = false;
if($t_lat > $bottom && $t_lat < $top && $t_lon > $left && $t_lon < $right)
$inside = true;
else if($second_right && $second_left)
{
if($t_lat > $bottom && $t_lat < $top && $t_lon > $second_left && $t_lon < $second_right)
$inside = true;
}
if($inside)
{
}
This seems to work with MKMapView since the region latitudes are always between -90 and 90.
This logic should work:
if ( ($X > $center_lat - $span_lat/2) &&
($X < $center_lat + $span_lat/2) &&
($Y > $center_lon - $span_lon/2) &&
($Y < $center_lon + $span_lon/2) ) {
echo "It's inside!";
} else {
echo "It's outside ...";
}
I had worked a solution for my own problem before, but for decimal values of coordinates and it works. May be if you can convert deg to decimal it might work.
I have renamed the variable according to your problem.
Here's the logic.
if
(
(
($lat - $spanLat) < $centerLat &&
$centerLat < ($lat+ $spanLat)
) &&
(
($long - $spanLong) < $centerLong &&
$centerLong < ($long + $spanLong)
)
)
What is a simple, elegant way to list the first x number of IPv6 IPs from a IPv6 string.
For example,
listIPs("2600:f333:10:c000::0", 4)
echos
2600:f333:10:c000::1
2600:f333:10:c000::2
2600:f333:10:c000::3
2600:f333:10:c000::4
Here's a sample of code that may have worked for IPv4, as it converted to int:
$input = "2600:f333:10:c000::/51";
$max = 4;
list($block, $cidr) = explode("/", $input);
$first = inet_pton( $block );
echo inet_ntop($first) . "\n";
for ($i = 1; $i < $max; $i++) {
//todo: die if it has exceeded block size based on $cidr
echo inet_ntop($first + $i) . "\n"; //doesn't work, packed binary?
}
Here's an example program written in C (since I don't know C++). It's fairly fast, but I'm not really happy with it. Maybe someone can help me improve it.
Edit: Obviously, I wrote this before it was turned into a PHP-only question. Turning this into PHP is left as an exercise to the reader (ew).
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
/*
* Syntax: ./ipv6_list <ip>/<cidr-prefix>
*/
int main(int argc, char **argv) {
uint8_t start[16];
uint8_t address[16];
uint8_t mask[16] = { 0 };
uint8_t prefix = 128;
char *prefix_location;
int i;
/* This is the octet that, when changed, will result in <IP> & <mask> != <start IP> */
int mask_check_octet = 0;
if(argc != 2)
return 1;
/* Find prefix */
if((prefix_location = strstr(argv[1], "/")) != NULL) {
char *prefix_search = prefix_location + 1;
char *prefix_remaining;
long prefix_test;
if(!isdigit(*prefix_search))
return 2;
errno = 0;
prefix_test = strtol(prefix_search, &prefix_remaining, 10);
if(errno == ERANGE || prefix_test < 0 || prefix_test > 128 || strcmp(prefix_remaining, "") != 0)
return 2;
prefix = (uint8_t)prefix_test;
*prefix_location = '\0'; /* So we can just pass argv[1] into inet_pton(3) */
}
/* Convert prefix into mask */
for(i = 0; i < 16; i++) {
if(prefix == 0)
break;
mask_check_octet = i;
if(prefix < 8) {
mask[i] = ~((1 << (8 - prefix)) - 1);
break;
}
else
mask[i] = UINT8_MAX;
prefix -= 8;
}
/* Find address */
if(inet_pton(AF_INET6, argv[1], start) != 1)
return 3;
/* Start at the beginning of the network */
for(i = 0; i < 16; i++) {
start[i] &= mask[i];
address[i] = start[i];
}
/* Iterate */
while((address[mask_check_octet] & mask[mask_check_octet]) == start[mask_check_octet]) {
char address_str[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, address, address_str, sizeof(address_str));
printf("%s\n", address_str);
/* Add one to the address */
for(i = 15; i >= 0; i--) {
if(address[i] != UINT8_MAX)
break;
}
address[i]++;
for(i++; i < 16; i++)
address[i] = 0;
};
return 0;
}
You can use standard shell commands to limit its output (or just modify the while loop):
nfontes#brioche:~$ ./ipv6_list '2607:fc50:0:d00::0/106' | head -n 200
2607:fc50:0:d00::
2607:fc50:0:d00::1
2607:fc50:0:d00::2
2607:fc50:0:d00::3
2607:fc50:0:d00::4
2607:fc50:0:d00::5
2607:fc50:0:d00::6
2607:fc50:0:d00::7
2607:fc50:0:d00::8
2607:fc50:0:d00::9
2607:fc50:0:d00::a
2607:fc50:0:d00::b
2607:fc50:0:d00::c
2607:fc50:0:d00::d
2607:fc50:0:d00::e
[...]
2607:fc50:0:d00::c0
2607:fc50:0:d00::c1
2607:fc50:0:d00::c2
2607:fc50:0:d00::c3
2607:fc50:0:d00::c4
2607:fc50:0:d00::c5
2607:fc50:0:d00::c6
2607:fc50:0:d00::c7
Something similar (in PHP). It takes an IPv4/IPv6 address and increments it by given value:
// Takes an IPv4/IPv6 address in string format, and increments it by given value
function incrementIp($ip, $increment)
{
$addr = inet_pton ( $ip );
for ( $i = strlen ( $addr ) - 1; $increment > 0 && $i >= 0; --$i )
{
$val = ord($addr[$i]) + $increment;
$increment = $val / 256;
$addr[$i] = chr($val % 256);
}
return inet_ntop ( $addr );
}
I'm having an asbolute nightmare dealing with an array of numbers which has the following structure :
Odd numbers in the array : NumberRepresenting Week
Even numbers in the array : NumberRepresenting Time
So for example in the array :
index : value
0 : 9
1 : 1
2 : 10
3 : 1
Would mean 9 + 10 on Day 1 (Monday).
The problem is, I have a an unpredictable number of these and I need to work out how many "sessions" there are per day. The rules of a session are that if they are on a different day they are automatically different sessions. If they are next to each other like in the example 9 + 10 that would count as a single session. The maximum number than can be directly next to eachother is 3. After this there needs to be a minimum of a 1 session break in between to count as a new session.
Unfortunately, we cannot also assume that the data will be sorted. It will always follow the even / odd pattern BUT could potentially not have sessions stored next to each other logically in the array.
I need to work out how many sessions there are.
My code so far is the following :
for($i = 0; $i < (count($TimesReq)-1); $i++){
$Done = false;
if($odd = $i % 2 )
{
//ODD WeekComp
if(($TimesReq[$i] != $TimesReq[$i + 2])&&($TimesReq[$i + 2] != $TimesReq[$i + 4])){
$WeeksNotSame = true;
}
}
else
{
//Even TimeComp
if(($TimesReq[$i] != ($TimesReq[$i + 2] - 1))&& ($TimesReq[$i + 2] != ($TimesReq[$i + 4] - 1)))
$TimesNotSame = true;
}
if($TimesNotSame == true && $Done == false){
$HowMany++;
$Done = true;
}
if($WeeksNotSame == true && $Done == false){
$HowMany++;
$Done = true;
}
$TimesNotSame = false;
$WeeksNotSame = false;
}
However this isn't working perfectly. for example it does not work if you have a single session and then a break and then a double session. It is counting this as one session.
This is, probably as you guessed, a coursework problem, but this is not a question out of a textbook, it is part of a timetabling system I am implementing and is required to get it working. So please don't think i'm just copy and pasting my homework to you guys!
Thank you so much!
New Code being used :
if (count($TimesReq) % 2 !== 0) {
//throw new InvalidArgumentException();
}
for ($i = 0; $i < count($TimesReq); $i += 2) {
$time = $TimesReq[$i];
$week = $TimesReq[$i + 1];
if (!isset($TimesReq[$i - 2])) {
// First element has to be a new session
$sessions += 1;
$StartTime[] = $TimesReq[$i];
$Days[] = $TimesReq[$i + 1];
continue;
}
$lastTime = $TimesReq[$i - 2];
$lastWeek = $TimesReq[$i - 1];
$sameWeek = ($week === $lastWeek);
$adjacentTime = ($time - $lastTime === 1);
if (!$sameWeek || ($sameWeek && !$adjacentTime)) {
if(!$sameWeek){//Time
$Days[] = $TimesReq[$i + 1];
$StartTime[] = $TimesReq[$i];
$looking = true;
}
if($sameWeek && !$adjacentTime){
}
if($looking && !$adjacentTime){
$EndTime[] = $TimesReq[$i];
$looking = false;
}
//Week
$sessions += 1;
}
}
If you want a single total number of sessions represented in the data, where each session is separated by a space (either a non-contiguous time, or a separate day). I think this function will get you your result:
function countSessions($data)
{
if (count($data) % 2 !== 0) throw new InvalidArgumentException();
$sessions = 0;
for ($i = 0; $i < count($data); $i += 2) {
$time = $data[$i];
$week = $data[$i + 1];
if (!isset($data[$i - 2])) {
// First element has to be a new session
$sessions += 1;
continue;
}
$lastTime = $data[$i - 2];
$lastWeek = $data[$i - 1];
$sameWeek = ($week === $lastWeek);
$adjacentTime = ($time - $lastTime === 1);
if (!$sameWeek || ($sameWeek && !$adjacentTime)) {
$sessions += 1;
}
}
return $sessions;
}
$totalSessions = countSessions(array(
9, 1,
10, 1,
));
This of course assumes the data is sorted. If it is not, you will need to sort it first. Here is an alternate implementation that includes support for unsorted data.
function countSessions($data)
{
if (count($data) % 2 !== 0) throw new InvalidArgumentException();
$slots = array();
foreach ($data as $i => $value) {
if ($i % 2 === 0) $slots[$i / 2]['time'] = $value;
else $slots[$i / 2]['week'] = $value;
}
usort($slots, function($a, $b) {
if ($a['week'] == $b['week']) {
if ($a['time'] == $b['time']) return 0;
return ($a['time'] < $b['time']) ? -1 : 1;
} else {
return ($a['week'] < $b['week']) ? -1 : 1;
}
});
$sessions = 0;
for ($i = 0; $i < count($slots); $i++) {
if (!isset($slots[$i - 1])) { // First element has to be a new session
$sessions += 1;
continue;
}
$sameWeek = ($slots[$i - 1]['week'] === $slots[$i]['week']);
$adjacentTime = ($slots[$i]['time'] - $slots[$i - 1]['time'] === 1);
if (!$sameWeek || ($sameWeek && !$adjacentTime)) {
$sessions += 1;
}
}
return $sessions;
}
Here is my little attempt at solving your problem. Hopefully I understand what you want:
$TimesReq = array(9,4,11,4,13,4,8,4,7,2,12,4,16,4,18,4,20,4,17,4);
// First just create weeks with all times lumped together
$weeks = array();
for($tri=0; $tri<count($TimesReq); $tri+=2){
$time = $TimesReq[$tri];
$week = $TimesReq[$tri+1];
$match_found = false;
foreach($weeks as $wi=>&$w){
if($wi==$week){
$w[0] = array_merge($w[0], array($time));
$match_found = true;
break;
}
}
if(!$match_found) $weeks[$week][] = array($time);
}
// Now order the times in the sessions in the weeks
foreach($weeks as &$w){
foreach($w as &$s) sort($s);
}
// Now break up sessions by gaps/breaks
$breaking = true;
while($breaking){
$breaking = false;
foreach($weeks as &$w){
foreach($w as &$s){
foreach($s as $ti=>&$t){
if($ti>0 && $t!=$s[$ti-1]+1){
// A break was found
$new_times = array_splice($s, $ti);
$s = array_splice($s, 0, $ti);
$w[] = $new_times;
$breaking = true;
break;
}
}
}
}
}
//print_r($weeks);
foreach($weeks as $wi=>&$w){
echo 'Week '.$wi.' has '.count($w)." session(s):\n";
foreach($w as $si=>&$s)
{
echo "\tSession ".($si+1).":\n";
echo "\t\tStart Time: ".$s[0]."\n";
echo "\t\tEnd Time: ".((int)($s[count($s)-1])+1)."\n";
}
}
Given $TimesReq = array(9,4,11,4,13,4,8,4,7,2,12,4,16,4,18,4,20,4,17,4); the code will produce as output:
Week 4 has 4 session(s):
Session 1:
Start Time: 8
End Time: 10
Session 2:
Start Time: 11
End Time: 14
Session 3:
Start Time: 16
End Time: 19
Session 4:
Start Time: 20
End Time: 21
Week 2 has 1 session(s):
Session 1:
Start Time: 7
End Time: 8
Hope that helps.
I'm trying to rewrite a pascal program to PHP, and don't understand what this part of pascal function do:
while (u[3] <> 1) and (u[3]<>0) and (v[3]<>0)do
begin
q:=u[3] div v[3];
for i:=1 to 3 do
begin
t:=u[i]-v[i]*q;
u[i]:=v[i];
v[i]:=t;
{writeln('u',i,'=',u[i],' v',i,'=',v[i]); }
end;
end;
if u[1]<0 then u[1]:=n+u[1];
rae:=u[1];
Please help to rewrite it to PHP.
Thanks.
A very literal translation of that code, should be this one:
while ($u[3] != 1 && $u[3] != 0 && $v[3] != 1 )
{
$q = floor($u[3] / $v[3]);
for ($i = 1; $i <= 3; $i++)
{
$t = $u[$i] - $v[$i] * $q;
$u[$i] = $v[$i];
$v[$i] = $t;
//writeln('u',i,'=',u[i],' v',i,'=',v[i]);
}
}
if ($u[1] < 0 )
$u1] = $n + $u[1];
$rae = $u[1];
Of course, u and v are arrays. Sorry for not giving any more info, but it's been like 10 years since Pascal and I last saw each other, but we had a profound romance for a long time, since I feel inlove for to hotties(C# and PHP) :)
while ($u[3] != 1) && ($u[3] != 0) && ($v[3] != 0) {
$q = floor($u[3] / $v[3]);
for ($i = 1; $i <= 3; $i++) {
$t = $u[$i] - $v[$i] * $q;
$u[$i] = $v[$i];
$v[$i] = $t;
echo "u$i={$u[$i]} v$i={$v[$i]}\n";
}
}
if ($u[1] < 0) {
$u[1] = $n + $u[1];
}
$rae = $u[1];
2 small corrections to David's code:
while ($u[3] != 1 && $u[3] != 0 && $v[3] != 1 )
should be
while ($u[3] != 1 && $u[3] != 0 && $v[3] != 0 )
and
for ($i = 1; $i < 3; $i++)
i never reaches the value of 3
for ($i = 1; $i <= 3; $i++)
May be the Writeln can be translated to
echo 'u'.$i.'='.$u[$i].' v'.$i.'='.$v[$i];
When you do the translation of arrays, take into account that arrays in php uses 0 as the first index.
$u= array( 3, 5, 22 )
echo u[1]; // prints 5
while($u[3] != 1 && $u[3] != 0 && $v[3] != 0)
{
$q = ($u[3] - ($u[3] % $v[3]) ) / $v[3]; //just the same as floor($u[3]/$v[3]), but i want to use % here :)
for ($i = 1; $i <= 3; $i++)
{
$t = $u[$i] - $v[$i]*$q;
$u[$i] = $v[$i];
$v[$i] = $t;
echo '<br />u'.$i.'='.$u[$i].' v'.$i.'='.$v[$i];
}
}
if ($u[1] < 0) $u[1] = $n + $u[1];
$rae = $u[1];
I dont know pascal But i have tried :)
while ($u[3]!=1 && $u[3]!=0 && $v[3]!=0) [
$q=floor($u[3]/ $v[3]);
for ($i=1;$i<3;$i++) {
$t=$u[$i]-$v[$i]*$q;
$u[$i]=$v[$i];
$v[$i]=$t;
echo "u".$i."=".$u[$i]."v".$i."=".$v[$i];
}
if ($u[1]<0) {
$u[1]=$n+$u[1];
}
$rae=$u[1];
In php variable Name Start With $
No Begin End used here in php only braces :)