Finding all points contouring the overlapping squares - php

The setup:
a. 2D surface
b. points (with x, y coordinates) which when connected form squares.
c. I found an algorithm that finds the intersection points of those squares so assume we have them as well.
The question is: how do I get points that contour the squares.
I've included an image for better understanding.
I was looking into http://en.wikipedia.org/wiki/Convex_hull_algorithms but it seems like they all skip those intersections (the 90' angles).
I am writing this in php but i'd love to even see a pseudo code if at all possible.

<?php
//WARNING! we assume coords as non-polar. for this to work on large-scale, you need to convert polar into decard coords.
//Can be done outside this script.
//Points sample:
$points_raw=json_decode('{"1":[[41.014357690351,-73.73715475406],[41.029170309649,-73.73715475406],[41.014357690351,-73.75644124594],[41.029178309649,-73.73721675406],[41.014365690351,-73.75650324594],[41.031554690351,-73.73806375406],[41.046091309649,-73.78489424594],[41.014688690351,-73.78819424594],[41.012691690351,-73.75993275406],[41.012691690351,-73.77921924594],[41.015809690351,-73.75893475406],[41.053689309649,-73.76006575406],[41.053689309649,-73.77935224594],[41.050793309649,-73.78376624594],[41.043862309649,-73.79638424594],[41.029049690351,-73.79638424594],[41.019350690351,-73.79608224594],[41.033268690351,-73.73637875406],[41.048081309649,-73.73637875406],[41.048081309649,-73.75566524594],[41.014365690351,-73.75644124594],[41.029170309649,-73.73721675406],[41.018165690351,-73.75650324594],[41.029178309649,-73.74662775406],[41.031554690351,-73.74662775406],[41.033268690351,-73.73806375406],[41.043862309649,-73.78489424594],[41.019350690351,-73.78819424594],[41.015809690351,-73.75993275406],[41.014688690351,-73.77921924594],[41.018165690351,-73.75893475406],[41.047266309649,-73.76006575406],[41.050793309649,-73.77935224594],[41.046091309649,-73.78376624594],[41.029049690351,-73.79608224594],[41.047266309649,-73.75566524594]]}',1);
//BEGIN HERE:
$points=$points_raw[1];
function to_round($val)
{
//here we can try conversion from polar to decard. not sure if will work
//no conversion for now, but just rounding for comparsion
return round($val*1000000000000);
}
function sort_points_array($a, $b, $which)
{
$da=to_round($a[$which]);
$db=to_round($b[$which]);
if ($da == $db) {
return 0;
}
return ($da < $db) ? -1 : 1;
}
function sort_by_0($a, $b)
{
return sort_points_array($a, $b, 0);
}
function sort_by_1($a, $b)
{
return sort_points_array($a, $b, 1);
}
//BEGIN OF UNOPTIMIZED SORT
//sort by columns from left to right (does not have to be left/right on the map)
//but we will try :) 0 -> Y, 1 -> X
//sort by X, so lower X will be on top of array.
//and each point in those columns will be also sorted from top to bottom by their Y
usort($points,"sort_by_1");
//then foreach to split array by "columns";
$column_counter=0;
$point_columns=array();
$point_columns[$column_counter][]=$points[0];
foreach($points as $n_point=>$p_coords)
{
if($n_point>0)
{
if(to_round($p_coords[1]) > to_round($point_columns[$column_counter][1][1]))
$column_counter++;
$point_columns[$column_counter][]=$p_coords;
}
}
//now sort each column
$sorted_point_columns=array();
foreach($point_columns as $pcn => $p_column)
{
usort($p_column,"sort_by_0");
$sorted_point_columns[$pcn]=$p_column;
}
//SAME TO MAKE sorted_point_rows
usort($points,"sort_by_0");
$row_counter=0;
$point_rows=array();
$point_rows[$row_counter][]=$points[0];
foreach($points as $n_point=>$p_coords)
{
if($n_point>0)
{
if(to_round($p_coords[0]) > to_round($point_rows[$row_counter][0][0]))
$row_counter++;
$point_rows[$row_counter][]=$p_coords;
}
}
$sorted_point_rows=array();
foreach($point_rows as $prn => $p_row)
{
usort($p_row,"sort_by_1");
$sorted_point_rows[$prn]=$p_row;
}
// END OF UNOPTIMIZED SORT
//output array
$final_points_poly=array();
//clearly first point will be from 1st row;
//and we will go to the RIGHT in current row to find next point
$final_points_poly[0]=$sorted_point_rows[0][0];
//and let the magic begin:
$finished=false;
$last_point_index=0;
$points_total=count($points);
$pos_x=0; //pos by columns
$pos_y=0; //pos by rows
$relative_X=0; //relative X position in current ROW;
$relative_Y=0; //relative Y position in current COLUMN;
$rule=1; // right / down = 1, left / up = -1
//detect if we go by X or Y
$going_Y=false;
$finished=false;
while(!$finished)
{
if($going_Y)
{
$relative_Y+=$rule;
$last_point_index+=1;
$cur_p=$sorted_point_columns[$pos_x][$relative_Y];
$final_points_poly[$last_point_index]=$cur_p;
$going_Y = !$going_Y;
//search for pos_y:
foreach($sorted_point_rows as $cur_y => $row)
{
if(to_round($row[0][0]) == to_round($cur_p[0]))
{
$pos_y=$cur_y;
//search for relative_X
foreach($row as $cur_rel_x => $check_point)
{
if(to_round($check_point[1]) == to_round($cur_p[1]))
{
$relative_X=$cur_rel_x;
$rule = ($relative_X % 2 == 0 ? 1 : -1);
break 2;
}
//error_check 1
if($cur_rel_x == count($row)-1)
echo "error with calculating relative_X! check your data!\n";
}
}
//error_check 2
if($cur_y == count($sorted_point_rows)-1)
echo "error with calculating pos_y! check your data!\n";
}
}
else
{
$relative_X+=$rule;
$last_point_index+=1;
$cur_p=$sorted_point_rows[$pos_y][$relative_X];
$final_points_poly[$last_point_index]=$cur_p;
$going_Y = !$going_Y;
//search for pos_x:
foreach($sorted_point_columns as $cur_x => $column)
{
if(to_round($column[0][1]) == to_round($cur_p[1]))
{
$pos_x=$cur_x;
//search for relative_Y
foreach($column as $cur_rel_y => $check_point)
{
if(to_round($check_point[0]) == to_round($cur_p[0]))
{
$relative_Y=$cur_rel_y;
$rule = ($relative_Y % 2 == 0 ? 1 : -1);
break 2;
}
//error_check 1
if($cur_rel_y == count($column)-1)
echo "error with calculating relative_Y! check your data!\n";
}
}
//error_check 2
if($cur_x == count($sorted_point_columns)-1)
echo "error with calculating pos_x! check your data!\n";
}
}
if($last_point_index == $points_total-1)
{
$finished=true;
}
}
echo "all points:\n";
print_r($final_points_poly);
/*
//generate markers for google mapping
$out = "var bbs=[];var markers=[];";
$out .= "var pinI = new google.maps.MarkerImage('http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|ADDE63');";
$out .= "var pinI2 = new google.maps.MarkerImage('http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|FF8C00');";
$out .= "var pinI3 = new google.maps.MarkerImage('http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|990099');";
$out .= "bbs.push(new google.maps.Polyline({ ";
$out .= "path: [";
foreach($final_points_poly as $m){
$out .= "new google.maps.LatLng(".join(",",$m)."),";
}
$out .= "],";
$out .= "strokeColor: 'black', strokeOpacity: 0.4, strokeWeight: 1 }));";
$f = fopen("bbs.js",'w');
fwrite($f,$out);
fclose($f);
*/
?>

Related

Matrix multiplication in php

Although the order of matrices should be fine, the following code throws back the exception. It might be a tiny thing I'm not being able to notice, but can't figure it out.
<?php
$mat1 = array(5,1);
$mat2 = array(1,5);
function matrixmult($m1,$m2){
$r=count($m1);
$c=count($m2[0]);
$p=count($m2);
if(count($m1[0])!=$p){throw new Exception('Incompatible matrixes');}
$m3=array();
for ($i=0;$i< $r;$i++){
for($j=0;$j<$c;$j++){
$m3[$i][$j]=0;
for($k=0;$k<$p;$k++){
$m3[$i][$j]+=$m1[$i][$k]*$m2[$k][$j];
}
}
}
}
return($m3);
}
matrixmult($mat1,$mat2);
?>
You're specifying your test matrices wrong, in two ways:
The arrays aren't two-dimensional (that is, arrays of arrays of numbers).
Even if you wrapped another array( ) around them, the condition that the width of the first matrix be equal to the height of the second matrix doesn't hold with [5 1] and [1 5], which are both 2 wide and 1 high.
What you need is something like
$mat1 = array(array(5,1));
$mat2 = array(array(1),array(5));
Just to round this out. Here is a working solution:
function M_mult($_A,$_B) {
// AxB outcome is C with A's rows and B'c cols
$r = count($_A);
$c = count($_B[0]);
$in= count($_B); // or $_A[0]. $in is 'inner' count
if ( $in != count($_A[0]) ) {
print("ERROR: need to have inner size of matrices match.\n");
print(" : trying to multiply a ".count($_A)."x".count($_A[0])." by a ".count($_B)."x".count($_B[0])." matrix.\n");
print("\n");
exit(1);
}
// allocate retval
$retval = array();
for($i=0;$i< $r; $i++) { $retval[$i] = array(); }
// multiplication here
for($ri=0;$ri<$r;$ri++) {
for($ci=0;$ci<$c;$ci++) {
$retval[$ri][$ci] = 0.0;
for($j=0;$j<$in;$j++) {
$retval[$ri][$ci] += $_A[$ri][$j] * $_B[$j][$ci];
}
}
}
return $retval;
}
}
You must delete the curly braces before return.
<?php
$mat1 = array(5,1);
$mat2 = array(1,5);
function matrixmult($m1,$m2){
$r=count($m1);
$c=count($m2[0]);
$p=count($m2);
if(count($m1[0])!=$p){throw new Exception('Incompatible matrixes');}
$m3=array();
for ($i=0;$i< $r;$i++){
for($j=0;$j<$c;$j++){
$m3[$i][$j]=0;
for($k=0;$k<$p;$k++){
$m3[$i][$j]+=$m1[$i][$k]*$m2[$k][$j];
}
}
}
return($m3);
}
matrixmult($mat1,$mat2);
?>

Display different prefix and suffix in CodeIgniter PHP

$all_categories=get_cats($cat);
$headingPrinted = false;
$childCount = 0;
for($i=0;$i<sizeof($all_categories);$i++)
{
$arr=get_gender($cat);
if($arr[$i]=='0')
{
if (!$headingPrinted) {
echo "&nbsp&nbsp"."Sons:";
$headingPrinted = true;
}
echo "&nbsp&nbsp".$all_categories[$i].",";
$childCount++;
}
}
if ($childCount >= 3) {
echo $childCount, $childCount == 1 ;
}
else {
// you may want to do something if none found
}
$headingPrinted = false;
$childCount = 0;
for($i=0;$i<sizeof($all_categories);$i++)
{
$arr=get_gender($cat);
if($arr[$i]=='1'){
if (!$headingPrinted) {
echo "&nbsp&nbsp"."Daughters:";
$headingPrinted = true;
}
echo "&nbsp&nbsp".$all_categories[$i].",";
$childCount++;
}
}
if ($childCount >= 3) {
echo $childCount, $childCount == 1 ;
}
else {
// you may want to do something if none found
}
I am displaying the word "Sons" then their names then their count and the word "daughters" then their names then count. I want to display like this:
Sons: a,b,c,d:4;
Daughters: p,q,r,s:4;
$all_categories is an array in which I'm getting all children of given ID and get_gender and get_cats are functions.
Now I'm displaying:
a,b,c,d, :4;
I want to display count only if:
count of sons is greater than 2 and same for daughters.
boys count is 1 then the word "Sons:"a; and same for daughters.
boys count is 2 then the word "Sons:" a,b; and same for daughters.
boys count is greater than 2 then the word "Sons:" a,b,c:3; and same for daughters.
I want to display result same like above I said. Thanks in advance
Anyone tried this...

PHP Error: Undefined offset: 10

I wrote a program that creates a puzzle based on user's inputs. There is a html form that accepts the user's words and posts them to the php program. Then the php program creates the puzzle and prints it.
There is a live demo here. You can type you own words.
It looks good but when I run it in my local server with php error prompt turned on, I see the error msg saying Undefined offset: 10 at line 147 and 148. The error is generated from the php code line starting from if ($board[$curr_row][$curr_col] == '.'... You can use Ctrl+F to find the code. I don't understand how could I get 10 in $curr_col or $curr_row since the loop should stop after they reach 9.
Please help me understand how could the loop run after they have reached 10, thanks a lot!
The zipped version of the program is here.
Here is the code of the php:
<html>
<body>
<?php
/* word Find
Generates a word search puzzle based on a word list entered by user.
User can also specify the size of the puzzle and print out
an answer key if desired
*/
//If there is no data from the form, prompt the user to go back
if (!filter_has_var(INPUT_POST, "puzzle_name")) {
print <<<MUL_LINE
<!DOCTYPE html>
<html >
<head>
<title>Oops!</title>
</head>
<body>
<p>This page should not be called directly, please visit
the puzzle form to continue.</p>
</body>
</html>
MUL_LINE;
} else {
$boardData = array("name" => filter_input(INPUT_POST, "puzzle_name"), "width" => filter_input(INPUT_POST, "grid_width"), "height" => filter_input(INPUT_POST, "grid_height"));
if (parseList() == TRUE) {//parse the word list in textarea to an array of words
//keep trying to fill the board untill a valid puzzle is made
do {
clearBoard();
//reset the board
$pass = fillBoard();
} while($pass == FALSE);
printBoard();
//if the board if successfully filled, print the puzzle
}
}//end word list exists if
//parse the word list in textarea to an array of words
function parseList() {
//get word list, creates array of words from it
//or return false if impossible
global $word, $wordList, $boardData;
$wordList = filter_input(INPUT_POST, "wordList");
$itWorked = TRUE;
//convert word list entirely to upper case
$wordList = strtoupper($wordList);
//split word list into array
$word = explode("\n", $wordList);
//an array of words
foreach ($word as $key => $currentWord) {
//trim all the beginning and trailer spaces
$currentWord = rtrim(ltrim($currentWord));
//stop if any words are too long to fit in puzzle
if ((strlen($currentWord) > $boardData["width"]) && (strlen($currentWord) > $boardData["height"])) {
print "$currentWord is too long for puzzle";
$itWorked = FALSE;
}//end if
$word[$key] = $currentWord;
}//end foreach
return $itWorked;
}//end parseList
//reset the board by filling each cell with "."
function clearBoard() {
//initialize board with a . in each cell
global $board, $boardData;
for ($row = 0; $row < $boardData["height"]; $row++) {
for ($col = 0; $col < $boardData["width"]; $col++) {
$board[$row][$col] = ".";
}//end col for loop
}//end row for loop
}//end clearBoard
//fill the board
function fillBoard() {
global $word;
$pass = FALSE;
//control the loop of filling words, false will stop the loop
//control the loop, if all the words are filled, the counter will be as equal to the number
//of elements in array $words, thus the loop stops successfully
$counter = 0;
do {
$pass = fillWord($word[$counter]);
//if a word is filled, $pass is set to true
$counter++;
}
//if a word can't be filled, pass==FALSE and loop stops
//or if all words are through, loop stops
while($pass==TRUE && $counter<count($word));
//return TRUE if all filled successfully, FALSE if not
if ($pass == TRUE && $counter == count($word)) {
return TRUE;
} else {
return FALSE;
}
}
//function used to fill a single word
function fillWord($single_word) {
global $board, $boardData;
//the direction of how the word will be filled, 50% chance to be H, and 50% chance to be V
$dir = (rand(0, 1) == 0 ? "H" : "V");
//H(horizontal) means fill the word from left to right
//V(vertical) means fill the word from up to down
//loop control. if a letter is not filled, $pass is set to false and loop stops
$pass = TRUE;
//loop control. if all letters are filled successfully, loop stops too.
$counter = 0;
//decide the cell to fill the first word. the cell is located at $board[$curr_row][$curr_col]
if ($dir == "H") {//if the word will be fileld from left to right
$curr_row = rand(0, $boardData["height"] - 1);
//pick up a random row of the 10 rows ( rand(0,9) )
$curr_col = rand(0, ($boardData["width"] - ( strlen($single_word - 1)) - 1));
//pick up a random column of fillable columns
//if the word is "banana" and the board's width
//is 10, the starting column can only be rand(0, 4)
} else if ($dir == "V") {//if the word will be fileld from up to down
$curr_row = rand(0, ($boardData["height"] - ( strlen($single_word - 1)) - 1));
$curr_col = rand(0, $boardData["width"] - 1);
} else {
print "invalid direction";
}
//the loop that keeps trying to fill letters of the word
while ($pass && ($counter < strlen($single_word))) {//while the $pass is true AND there are still letters
//to fill, keep the loop going
//the next line and the line after generate the msg "Undefined offset: 10",
//$curr_row and $curr_col should never be 10 because the loop should be stopped
//if the last letter of the word is filled
if ($board[$curr_row][$curr_col] == '.' || //if the cell is not filled, reset fillboard() to "."
$board[$curr_row][$curr_col] == substr($single_word, $counter, 1))//or it has already been filled with the same letter
{
$board[$curr_row][$curr_col] = substr($single_word, $counter, 1);
// write/fill the letter in the cell
$counter++;
if ($dir == "H") {
$curr_col++;
//next column, move to the next right cell
} else if ($dir == "V") {
$curr_row++;
//next row, move to the next lower cell
} else {
print "\nHuge direction error!";
}
} else {
$pass = FALSE;
// failed to fill a letter, stop the loop
}
}
//if all the letters are filled successfully, the single word is filled successfully
//return true, let $fillBoard go filling next single word
if ($pass && ($counter == strlen($single_word))) {
/* for debug purpose
print "<hr />";print "<p>TRUE</p>";print "<hr />";
print $single_word;
print $curr_row . "," . $curr_col . "<br />";
print "<hr />";*/
return TRUE;
} else {
//failed to fill the word, reset the board and start all over again
return FALSE;
}
}//end function fillWord
//print the successful filled puzzle
function printBoard() {
global $board;
print <<<MULLINE
<style type="text/css">
table, td{
border: 1px solid black;
}
</style>
MULLINE;
print '<table >';
foreach ($board as $row) {
print '<tr>';
foreach ($row as $cell) {
print '<td>';
print $cell;
print '</td>';
}
print("<br />");
print '</tr>';
}
print "</table>";
}
?>
</body>
</html>
I don't think the following fragment of code is right.
strlen($single_word - 1)
located in the lines:
$curr_col = rand(0, ($boardData["width"] - ( strlen($single_word - 1)) - 1));
and
$curr_row = rand(0, ($boardData["height"] - ( strlen($single_word - 1)) - 1));
It will convert the word to an integer. Subtract one from that number. Then convert that back to a string and take the length. So you have a rubbish value for the length.

PHP loops to check that a set of numbers are consecutive

I'm trying to loop through a set of records, all of which have a "number" property. I am trying to check if there are 3 consecutive records, e.g 6, 7 and 8.
I think i'm almost there with the code below, have hit the wall though at the last stage - any help would be great!
$nums = array();
while (count($nums <= 3))
{
//run through entries (already in descending order by 'number'
foreach ($entries as $e)
{
//ignore if the number is already in the array, as duplicate numbers may exist
if (in_array($e->number, $num))
continue;
else
{
//store this number in the array
$num[] = $e->number;
}
//here i need to somehow check that the numbers stored are consecutive
}
}
function isConsecutive($array) {
return ((int)max($array)-(int)min($array) == (count($array)-1));
}
You can achieve the same result without looping, too.
If they just have to be consecutive, store a $last, and check to make sure $current == $last + 1.
If you're looking for n numbers that are consecutive, use the same, except also keep a counter of how many ones fulfilled that requirement.
$arr = Array(1,2,3,4,5,6,7,343,6543,234,23432,100,101,102,103,200,201,202,203,204);
for($i=0;$i<sizeof($arr);$i++)
{
if(isset($arr[$i+1]))
if($arr[$i]+1==$arr[$i+1])
{
if(isset($arr[$i+2]))
if($arr[$i]+2==$arr[$i+2])
{
if(isset($arr[$i+3]))
if($arr[$i]+3==$arr[$i+3])
{
echo 'I found it:',$arr[$i],'|',$arr[$i+1],'|',$arr[$i+2],'|',$arr[$i+3],'<br>';
}//if3
}//if 2
}//if 1
}
I haven't investigated it thoroughly, maybe can be improved to work faster!
This will confirm if all items of an array are consecutive either up or down.
You could update to return an array of [$up, $down] or another value instead if you need direction.
function areAllConsecutive($sequence)
{
$up = true;
$down = true;
foreach($sequence as $key => $item)
{
if($key > 0){
if(($item-1) != $prev) $up = false;
if(($item+1) != $prev) $down = false;
}
$prev = $item;
}
return $up || $down;
}
// areAllConsecutive([3,4,5,6]); // true
// areAllConsecutive([3,5,6,7]); // false
// areAllConsecutive([12,11,10,9]); // true
Here's an example that can check this requirement for a list of any size:
class MockNumber
{
public $number;
public function __construct($number)
{
$this->number = $number;
}
static public function IsListConsecutive(array $list)
{
$result = true;
foreach($list as $n)
{
if (isset($n_minus_one) && $n->number !== $n_minus_one->number + 1)
{
$result = false;
break;
}
$n_minus_one = $n;
}
return $result;
}
}
$list_consecutive = array(
new MockNumber(0)
,new MockNumber(1)
,new MockNumber(2)
,new MockNumber(3)
);
$list_not_consecutive = array(
new MockNumber(5)
,new MockNumber(1)
,new MockNumber(3)
,new MockNumber(2)
);
printf("list_consecutive %s consecutive\n", MockNumber::IsListConsecutive($list_consecutive) ? 'is' : 'is not');
// output: list_consecutive is consecutive
printf("list_not_consecutive %s consecutive\n", MockNumber::IsListConsecutive($list_not_consecutive) ? 'is' : 'is not');
// output: list_not_consecutive is not consecutive
If u don't wanna mess with any sorting, picking any of three numbers that are consecutive should give you:
- it either is adjacent to both the other numbers (diff1 = 1, diff2 = -1)
- the only number that is adjacent (diff = +-1) should comply the previous statement.
Test for the first condition. If it fails, test for the second one and under success, you've got your secuence; else the set doesn't comply.
Seems right to me. Hope it helps.
I think you need something like the following function (no need of arrays to store data)
<?php
function seqOfthree($entries) {
// entries has to be sorted descending on $e->number
$sequence = 0;
$lastNumber = 0;
foreach($entries as $e) {
if ($sequence==0 or ($e->number==$lastNumber-1)) {
$sequence--;
} else {
$sequence=1;
}
$lastNumber = $e->number;
if ($sequence ==3) {
// if you need the array of sequence you can obtain it easy
// return $records = range($lastNumber,$lastNumber+2);
return true;
}
}
// there isn't a sequence
return false;
}
function isConsecutive($array, $total_consecutive = 3, $consecutive_count = 1, $offset = 0) {
// if you run out of space, e.g. not enough array values left to full fill the required # of consecutive count
if ( $offset + ($total_consecutive - $consecutive_count ) > count($array) ) {
return false;
}
if ( $array[$offset] + 1 == $array[$offset + 1]) {
$consecutive_count+=1;
if ( $consecutive_count == $total_consecutive ) {
return true;
}
return isConsecutive($array, $total_consecutive, $consecutive_count, $offset+=1 );
} else {
return isConsecutive($array, $total_consecutive, 1, $offset+=1 );
}
}
The following function will return the index of the first of the consecutive elements, and false if none exist:
function findConsecutive(array $numbers)
{
for ($i = 0, $max = count($numbers) - 2; $i < $max; ++$i)
if ($numbers[$i] == $numbers[$i + 1] - 1 && $numbers[$i] == $numbers[$i + 2] - 2)
return $i;
return false;
}
Edit: This seemed to cause some confusion. Like strpos(), this function returns the position of the elements if any such exists. The position may be 0, which can evaluate to false. If you just need to see if they exist, then you can replace return $i; with return true;. You can also easily make it return the actual elements if you need to.
Edit 2: Fixed to actually find consecutive numbers.

php: how to add odd/even loop in array

here is my code: http://www.pcgage.net/code.zip (sorry, pasting the code caused it to really mess up, even using the code container).
Scroll to line: 160 (to 174) - this is the loop in question. i want to make it so this is the even part, and then some code to make an odd part, so the loop repeats in this order. The reason is that i want to change the content of this loop alternately.
I am not a coder, so the best thing you could do is to post up the new code and i'll add it in where you tell me too, otherwise i'll get lost :)
Hope that makes sense, if not you can check an earlier post about this issue that explains why i need this (after finding out that css alone cannot solve my problem): css/php: how to solve this div float problem / odd even loop in array
this is the loop:
} elseif ( ( $findpost->ID ) != $id ) {
// all other posts except the current post
$serp_list_li[] = '<div class="serial-contain">
<div class=""><h5>' . $findpost->post_title . '</h5></div>
<div class="text-align">' . $findpost->post_excerpt . ' </div>
<div class="date"> ' . mysql2date('M jS, Y', $findpost->post_date) . ' at ' . mysql2date('g:ia', $findpost->post_date) . '</div>
<div class="comments"><b>' . $findpost->comment_count . ' Comments</b></div>
</div>' . "\n";
}
else {
The three ways are
Modulo
for ($i = 0; $i < 10; $i++)
{
if ($i % 2 == 0)
{
echo "even";
}
else
{
echo "odd";
}
}
Flipping boolean value
$even = true;
for ($i = 0; $i < 10; $i++)
{
if ($even)
{
echo "even";
}
else
{
echo "odd";
}
$even = !$even;
}
And mentioned boolean operator
for ($i = 0; $i < 10; $i++)
{
if ($i & 1 == 0)
{
echo "even";
}
else
{
echo "odd";
}
}
The most fastest is boolean operator. But the most robust is flipping method if you have very different numbers (like running through ID numbers and some are missing).
I haven't looked over the code, but if it's using a variable to count the loop number you can do:
for($i=0;$i<$blah;$i++)
if($i&1){
// ODD
}else{
// EVEN
}
EDIT(1):
I looked at the section you are running into, and now I have another problem, I'm unsure how you are judging what should be odd or not, so I propose two answers:
1: odd loop itteration:
/* Populate the post list array */
// Add here:
$oddLoop = false;
foreach ($findposts as $findpost):
//.....
if($oddLoop=!$oddLoop){
// code for odd loop numbers
}else{
// code for even loop numbers
}
2: Odd ID number:
} elseif ( ( $findpost->ID ) != $id ) {
if($findpost->ID & 1){
// ODD
}else{
//EVEN
}
For loops increment by 1:
$state = 'odd';
for (...)
{
$state = ($state == 'even' ? 'odd' : 'even');
echo $state . PHP_EOL;
}
Output:
even
odd
even
odd
...
If you ever delete an article you could be in trouble - your code assumes that ID runs (odd,even,odd,even) etc.
A better idea would be to create a separate iterator object to feed you the necessary values at each step. Here's what I use:
class LoopingPropertyIterator implements Iterator
{
private $startat = 0, $position = 0;
private $propertylist = array(
'boolean' => array(false, true),
'day' => array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'),
'dow' => array('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')
);
public function __construct($args, $startat = 0)
{
$this->startat = (int)$startat;
$this->position = $this->startat;
foreach ($args as $name => $arr)
$this->__set($name, $arr);
}
public function __get($name)
{
if (!array_key_exists($name, $this->propertylist))
throw new Exception(__METHOD__ . " unknown property $name");
$t =& $this->propertylist[$name];
if (is_array($t))
return $t[$this->position % count($t)];
else
return $t;
}
public function __set($name, $arr)
{
$this->propertylist[$name] = $arr;
}
public function current()
{
return $this->position;
}
public function key()
{
return $this->position;
}
public function next()
{
++$this->position;
}
public function rewind()
{
$this->position = $this->startat;
}
public function valid()
{
return true;
}
}
then your output simplifies to
$iter = new LoopingPropertyIterator( array(
'outerclass' => array('serial-contain-right','serial-contain-left'),
'innerclass' => array('text-align2','text-align')
));
...
elseif ( $findpost->ID != $id ) {
$link = get_permalink($firstpost->ID);
$title = $findpost->post_title;
$datetime = mysql2date('M jS, Y', $findpost->post_date).' at '.mysql2date('g:ia', $findpost->post_date);
$serp_list_li[]=
<<<TEXT
<div class="{$iter.outerclass}">
<div class="title">
<h5>{$title}</h5>
</div>
<div class="{$iter->innerclass}">{$findpost->excerpt}</div>
<div class="date">{$date}</div>
<div class="comments">
<a href="{$link}#comments"> title="{$title}">
<b>{$findpost->comment_count} Comments</b>
</a>
</div>
</div>
TEXT;
$iter->next();
}
Are you sure $findpost->ID contains sequential numbers?
You could replace the if/else with s short ternary statement like this:
$side = empty($side) || $side == 'right' ? 'left' : 'right';
$serp_list_li[] = '<div class="serial-contain-' . $side . '">' // ...the rest
This would add a 'left' side first.
Get EvenArray and OddArray
NSArray *numberArray = [NSArray arrayWithObjects:#1,#2,#3,#4,#6,#8,#10, nil];
for (id object in numberArray)
{
if ([object integerValue] % 2 == 0)
{
[evenArray addObject:object];
}
else
{
[oddArray addObject:object];
}
}

Categories