I'm pretty new to PHP but I have built some fairly simple WordPress themes in my time. I'm trying to make something unique and I'm not sure how to accomplish it (or if it's even possible).
My goal is to create a loop that will dynamically close rows when it reaches the column "12" count for bootstrap (IE: col-md-3 + col-md-3 + col-md-6 = 12). The look I'm ultimately trying to achieve and how I currently have my static file set up => https://jsfiddle.net/y2mLr3hd/7/embedded/result/. I'm only using "display: flex;" for right now to just demonstrate what I'm trying to achieve. I'd like it be just rows rather than a single row.
I'm use to the standard loop for WordPress using ULs and LIs but I have no idea on how to go about what I'm trying to do. I'd like the loop to figure a random number for the column size consisting of the column sizes "3, 4, 6, 8" and create rows with columns sizes equaling "12" like I stated before. THAT or find a way on how to make it work with the way I currently have it set up.
This is the closest thing to what I'm looking for but really isn't even that close =>https://stackoverflow.com/questions/16427962/twitter-bootstrap-spans-in-dynamic-websites#=. Here's the code from that link for quick reference:
$i=0;
foreach ($posts as $post):
if ($i%2==0) echo '<div class="row-fluid">';
echo '<div class="span6">'. $post->content .'</div>';
if ($i%2==1) echo '</div>';
$i++;
endforeach;
Any help on how I might be able to go about this would be GREATLY appreciated!
There are two parts to your question:
How to divide 12 in random parts using 3, 4, 6, and 8
Given an array of numbers that add up to 12, how to generate a row with posts?
The first one is more a mathematics question. Note that you can only combine 3s and 6s, or 4s and 8s. You cannot combine 3 and 4, and still get 12.
We'll devise a simple algorithm with this in mind:
function getRandomNumbers()
{
// We start with an empty array and add numbers until we hit 12.
$result = array();
// We choose either 3 or 4 as basic number.
$x = mt_rand(3, 4);
// Now, as long as we don't hit 12, we iterate through a loop,
// adding either the basic number, or 2 times the basic number:
while (array_sum($result) < 12) {
// Randomly decide
if (mt_rand(0, 1) > 0) {
$newElement = 2 * $x; // This is either 6 or 8
// However, always make sure not to exceed 12:
if (array_sum($result) + $newElement > 12) {
$newElement = $x;
}
} else {
$newElement = $x; // This is either 3 or 4
}
// Add the new number to the array:
$result[] = $newElement;
}
// Return the resulting array
return $result;
}
Now we need to use these arrays to create rows. We start by generating an array with random numbers with the function we wrote.
We'll simply iterate through the posts, use the numbers in the array until there's none left. We'll generate a new array with random numbers whenever we need a new one. Since that means we have added 12 width-worth of columns, that's the point where we need to start a new row as well.
// Get the initial array with random numbers
$randomArray = getRandomNumbers();
// Open the initial row.
echo '<div>';
foreach ($posts as $post):
if (count($randomArray) < 1) {
// Close the row and start a new one:
echo '</div><div>';
// Get a fresh array with random numbers:
$randomArray = getRandomNumbers();
}
$nextRandomNumber = array_pop($randomArray); // This takes the next number.
echo '<div class="col-md-' . $nextRandomNumber . '">'. $post->content .'</div>';
endforeach;
echo '</div>'; // Close the final row.
Related
I've been struggling to make the following piece of code more efficient.
In short;
I've got a database with titles and descriptions. The database will average on 10000 texts. I want to search compare these texts by splitting the text with 'mb_split' and then loop through all other texts to compare if the word exists. Depending on how many comparisons were made, I want to write the article numbers to another table in that database.
The following code works and does the trick, but it takes a really long time to finish and uses a lot of resources. I can't seem to find a way to compare these texts more efficiently.
function compareArticle() {
include '../include/write.php';
$readNewsQuery = "select title,text,articleid,name from texts";
$readNews = $dbwrite->query($readNewsQuery);
if ($readNews) {
//Fetch mysql data as an array
$news = $readNews->fetch_all(MYSQLI_NUM);
// Start foreach to read every article once
foreach ($news as $item) {
echo $item[2].'<br />';
// Start another foreach to loop through the articles to compare with
foreach ($news as $compare) {
$strippedWords = mb_split(' +', $item[0]);
$count = 0;
$compareString = "";
$compareString .= $compare[0];
$compareString .= $compare[1];
$compareString = strtolower($compareString);
// Start yet another foreach to loop through the words
foreach ($strippedWords as $word) {
// I only want to count the words that are longer than 4 characters
if (strlen($word) > 4) {
$woord = strtolower($word);
if (strpos($compareString, $word) && $compare[2] != $item[2]) {
$count++;
}
}
}
if ($count > 5) {
echo $count.'<br />';
//Insert action to write comparison to database (item[2] and compare[2])
}
}
}
}
}
What I'd really like to know; Can I be more efficient? Could I use less loops, or is there an easier way to search the array? If I can be more efficient, could someone give me a nudge in the right direction?
EDIT:
It might be useful to know what data I retrieve and what I want to write to another table:
texts-database is set up to include
| article id | title | text | sourcename
I compare the words in a title with the words of title and text combined for all other articles. If they match enough, I want to write both article id's to another table:
| id | original article id | compared article id |
Once you loop through a news item, you no longer need to compare any other news items to it, for example, if news item 1 didn't match the other 50 news items then when you start checking news item 2 you already know that it doesn't match news item 1.
So instead of looping through the news items twice, you can start your second loop on the current index +1 (you don't need to compare the current news item with itself) of your first news article loop.
Edit: Heres an example loop:
Optimized Loop:
$matches = array();
$a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 ];
$count = 0;
for ($i = 0; $i < count($a); ++$i) {
for ($j = $i+1; $j < count($a); ++$j) {
if ($a[$i] == $a[$j]) {
array_push($matches, "$i, $j");
}
$count++;
}
}
echo "Optimized n loops: $count\n";
echo 'Matches: ' . count($matches);
// Output
// Optimized n loops: 435
// Matches: 5
Un-optimized Loop
$matches = array();
$count = 0;
for ($i = 0; $i < count($a); ++$i) {
for ($j = 0; $j < count($a); ++$j) {
if ($a[$i] == $a[$j]) {
array_push($matches, "$i, $j");
}
$count++;
}
}
$matches = array_unique($matches); // Dedupe
echo "Un-optimized n loops: $count\n";
echo 'Matches: ' . count($matches);
// Output
// Un-optimized n loops: 900
// Matches: 40
The unoptimized loop includes a lot of duplicate matches (index 1 matches index 5, index 5 matches index 1)
I've executed a lot of tests and made a few changes to my script and now know what the biggest culprit was.
Original case:
Sample size of 10.000;
Execution time: over 600 seconds (ran into max execution time).
Test case:
Completely stripped down version of the original
Sample size of 1000;
Execution time: 24 seconds.
What made the biggest difference?
The biggest difference was changing the location of the following line:
$strippedWords = mb_split(' +', $item[0]);
I moved that line to the first loop instead of the second. This way the title from the first loop only gets split once every 1000 items instead of 1000 times every 1000 items. I measured the differences in time:
mb_split in the second loop:
Total execution time in seconds: 162.17704296112
mb_split in the first loop:
Total execution time in seconds: 24.564566135406
That's an amazingly huge difference. I'm guessing mb_split isn't the easiest thing for PHP to do. Putting mb_split in the wrong part of my code made the script almost 7 times slower :|
strtolower()
After that result, I was curious what differences I could make changing the location of other text modifiers. So, I took strtolower() and put that, where possible, in the first loop as well.
strtolower() in second loop:
Total execution time in seconds: 44.315208911896
strtolower() in first loop:
Total execution time in seconds: 37.129139900208
Although this difference is a lot smaller, it's still a notable difference.
A possible other cause
I am not sure -- as I don't currently have the time to test this -- if this is completely true, but while testing a few cases I found my browser was acting up. When I told PHP to output a lot of information to my browser, the scripts felt like they would run longer and the browser would stop showing information after a while, too.
If the occasion arrises and I have some spare time left, I'll be testing this theory and try to see if my browser can actually screw with the duration of my PHP scripts. I can't seem to find a logical reason as to why it would impact the duration of my PHP script, as I expect the browser to just crash and my PHP script to continue working server sided... but the thought crossed my mind a few times.
anyway, here's the new script
function compareArticle() {
//For timing my script
$time_start = microtime(true);
include '../include/write.php';
$readNewsQuery = "select title,text,articleid,name,datetoday from texts";
$readNews = $dbwrite->query($readNewsQuery);
$dateToday = date("Y-m-d");
if ($readNews) {
//Fetch mysql data as an array
$news = $readNews->fetch_all(MYSQLI_NUM);
}
foreach ($news as $item) {
// Decrease the sample pool
if ($item[4] != $dateToday) {
continue;
}
$strippedWords = strtolower($item[0]);
$strippedWords = mb_split(' +', $strippedWords);
// Start another foreach to loop through the articles to compare with
foreach ($news as $compare) {
$compareString = "";
$compareString .= $compare[0];
$compareString .= $compare[1];
$count = 0;
// Start yet another foreach to loop through the words
foreach ($strippedWords as $word) {
// I only want to count the words that are longer than 4 characters
if (strlen($word) > 4) {
if (strpos(strtolower($compareString), $word)) {
$count++;
}
}
}
I'm trying to build a little program to automatize a little task; in it, one can write two values (as inputs in a form) and then, in another page, numbers will be written in rows and columns with all the numbers within the range given.
The thing is... There will (almost always) be 500 numbers in the range, so I want the result to be displayed in 10 columns of 50 rows each, something like this image:
I wanted the result page (the one with all the numbers) to THEN give the possibility to export this as xml or pdf, but that's another story..
By now, I just would like to get the display right.
I'm using HTML and PHP on XAMPP. I've been able to get the first column... but can't get to the generations of the others, like this (and so on until 50):
So far, this is what I have, I'll put here my PHP code, because I don't think the HTML is relevant (but will post it too if it's needed) - (The values are passed by POST method)
<?php
$cont = 0;
$i = 0;
$arrayValues = range($valueFrom, $valueTo);
if($cont <= 50){
echo "<tr>";
for($i = 0; $i < 50; $i++){
echo "<p>$arrayValues[$i]</p>";
$cont++;
}
echo "</tr>";
}
?>
Also, using something like this --> Use PHP to Generate HTML table with static Cell Count of MySQL Data and worked ok, but I would the numbers displayed in columns... so not in rows (horizontally), so..
YES | NO
1 4 7 | 1 2 3
2 5 8 | 4 5 6
3 6 9 | 7 8 9
That's why I stopped trying with tables and just used a tag for the result.
EDIT:
So, given the "start" value and "end" value for a range, I would like to be able to print all those values in 10 columns of 50 rows each (so when it reaches 50 rows in the first column, it automatically moves to a new column and so on), and vertically (like the little diagram I tried to put above this, in the "YES" side)
Any ideas or guidance will be appreciated! :)
Have a nice rest of the week!
You can do this by splitting your range up into chunks and indexing into the resulting array of columns in a nested loop.
<table>
<?php
$valueFrom = 1;
$valueTo = 500;
$rowCount = 50;
$columns = array_chunk(range($valueFrom, $valueTo), $rowCount);
$columnCount = count($columns);
for ($row = 0; $row < $rowCount; $row++) {
echo '<tr>';
for ($column = 0; $column < $columnCount; $column++) {
$number = $columns[$column][$row] ?? '';
echo "<td>$number</td>";
}
echo '</tr>';
}
?>
</table>
PHP is an alien language for me. I am trying to pull some fields from WP's SQL database.. The content comes out okay but is a lot. I want to somehow put it in a HTML carousel or some slider, where data must be formatted like this:
<holder1>
<data1></data1>
<data2></data2>
<data3></data3>
</holder1>
<holder2>
<data4></data4>
<data5></data5>
<data6></data6>
</holder2>
I imagine I would have to put some for loop for i<4, do, then break into holder2.
Current script that echos the data =
while($row = mysql_fetch_array($rs)) {
echo "<div class='testimonials flexslider'><ul class='slides'><li class='testimonial flex-active-slide'><blockquote><p>" . $row['post_content'] . "</p><cite><span>" . $row['post_title'] . "</cite></span></blockquote></li></ul></div>"; }
I would like it to break after 3 <li> items each, into a seperate <div> or <article> whatever I find suitable according to the carousel I use.
You need an index variable, which echoes the beginning of the wrapper when it is divisible by 3, and the end of the wrapper when it leaves a remainder of 2 after division by 3 (and at the very end). It seems like this code would work:
$index = 0;
while($row = mysql_fetch_array($rs)) {
if ($index % 3 == 0) {
echo "<div class='testimonials flexslider'><ul class='slides'>";
}
echo "<li class='testimonial flex-active-slide'><blockquote><p>" . $row['post_content'] . "</p><cite><span>" . $row['post_title'] . "</cite></span></blockquote></li>";
if ($index % 3 == 2) {
echo "</ul></div>";
}
$index++;
}
if ($index % 3 != 2) {
echo "</ul></div>";
}
EDIT: a little bit of explanation to clarify the math. Suppose you have 10 results. Because we usually count from 0 in programming, they can be numbered 0 up to 9. This would make your structure look like this:
<holder>
<data0></data0>
<data1></data1>
<data2></data2>
</holder>
<holder>
<data3></data3>
<data4></data4>
<data5></data5>
</holder>
<holder>
<data6></data6>
<data7></data7>
<data8></data8>
</holder>
<holder>
<data9></data9>
</holder>
You see that we need a <holder> before elements 0, 3, 6 and 9 - all numbers which are divisible by 3. Mathematically, this is expressed with help of the remainder function - a number is divisible by 3 when its remainder after dividing by 3 is zero.
Likewise, we need a </holder> after elements 2, 5 and 8 - numbers which after division by 3 leave a remainder of 2.
We need to take care of the situation where the last block is not complete; that's why there's an extra block of code to take care of the last </holder>.
Newbie here, working on their second ever function. I've googles a bit on my problem, looked at PHP.net and at some articles on stack overflow, WC3schools, CoralCode, etc., but i haven't found anything that I can understand as of yet (i've done my diligence before come begging I promise).
The concept of my function is that it will take an array of whatever size, and print it out in rows of four. Function currently returns repeats itself overall equal to the size of the array. So if the array has 8 items, it returns nine groups (groupings defined visually by having the white line between them) of nine items. The first and the last have 16 boxes in them, 2-8 have 32 boxes in them where i was hoping to get back two rows of four with a while line between the two rows
see here for visual error
see here for how it's meant to look
So to sum up, my loop is over iterating/returning too much/not returning the data in the way i hoped. I'm not sure how to phrase the question, but i've done my best to ask it as best I can.
function PrintFolio($aaPlaceholder)
{
//print out two rows of four from array with 8 items
//if array had 7 items, then print row of 4 next row 3
//if array had 16 items, print 4 rows of 4, etc.
$height = sizeof($aaPlaceholder);//get size of array
//loop through array of X items, for each group of 4 print as a row
for($row = 0; $row < $height; $row++) //looping through the rows
{
echo '<div class="row flush">'; //open div
for($image = 0; $image < 4; $image++) //each row is composed of 4 images
{
foreach($aaPlaceholder as $key => $value) {
printf(TEMPLATE_PORTFOLIO, $key, $value);
//replaced $template with constant TEMPLATE_PORTFOLIO!
}
}
echo '</div>'; //end div group of 4
}//end loop
}//end function
If the answer is obvious, please remember i'm very new and it's not obvious to me or honestly I would not be asking.
Thank you for any help or guidance
cheers
First, the height is not the size of the array but it is a fourth of it.
Second, the inner foreach, as already stated in the comments, should not be changed: it should be deleted. You are already looping through your elements, no need to do it once more.
function PrintFolio($aaPlaceholder)
{
//print out two rows of four from array with 8 items
//if array had 7 items, then print row of 4 next row 3
//if array had 16 items, print 4 rows of 4, etc.
$itemsCount = sizeof($aaPlaceholder);//get size of array
$height = (int)ceil(sizeof($aaPlaceholder)/4);//get size of array divided by 4
//loop through array of X items, for each group of 4 print as a row
for($row = 0; $row < $height; $row++) //looping through the rows
{
echo '<div class="row flush">'; //open div
for($image = 0; $image < 4; $image++) //each row is composed of 4 images
{
$aaPlaceholderIndex = $row*4+$image; //the index in the original array
if( $aaPlaceholderIndex < $itemsCount ) {
printf(TEMPLATE_PORTFOLIO, $aaPlaceholderIndex, $aaPlaceholder[$aaPlaceholderIndex]);
}
}
echo '</div>'; //end div group of 4
}//end loop
}//end function
EDIT: this works if your array has plain numeric keys from 0 to n. Otherwise (e.g. associative array) it should read $aaPlaceholderIndex = array_keys($aaPlaceholder)[$row*4+$image];
EDIT AGAIN: so you use associative arrays (key are strings and not integers 0..n). I rushed a bit my edit about this. You'd better:
define $keys = array_keys($aaPlaceholder); outside the loops, where you define $height
define $aaPlaceholderIndex = $keys[$row*4+$image];
move this definition inside the "if" statement, which becomes
if( $row*4+$image < $itemsCount ) {
$aaPlaceholderIndex = $keys[$row*4+$image];
printf(TEMPLATE_PORTFOLIO, $aaPlaceholderIndex, $aaPlaceholder[$aaPlaceholderIndex]);
}
This way you run array_keys just once (good for performance) and you avoid a Notice "Undefined offset" when retrieving $keys[$row*4+$image] when $row*4+$image is too big.
This is probably not the best answer, but this is what I figured out to do.
I created a new variable called 'limit' which is equal to the height var divided by four. I then commented out the second 'for loop' as it was causing problems, leaving only the first for loop and the foreach loop. This gave me back my array as hoped.
Revised code below:
function PrintFolio($aaPlaceholder)
{
//print out two rows of four from array with 8 items
//if array had 7 items, then print row of 4 next row 3
//if array had 16 items, print 4 rows of 4, etc.
$height = sizeof($aaPlaceholder);//get size of array
$limit = $height % 4;
//loop through array of X items, for each group of 4 print as a row
for($row = 0; $row <= $limit; $row++) //looping through the rows
{
echo '<div class="row flush">'; //open div
//for($image = 0; $image < 4; $image++) //each row is composed of 4 images
//{
foreach($aaPlaceholder as $key => $value) {
printf(TEMPLATE_PORTFOLIO, $key, $value);
//replaced $template with constant TEMPLATE_PORTFOLIO!
}
//}
echo '</div>'; //end div group of 4
}//end loop
}//end function
$count=0;
$numb=50;
foreach ($sepkeys as $dbkey)
{
for ($page=10;$page<=$numb;$page=$page + 10)
{
// the if block
$count=$count+1;
}
}
I am trying to maintain a separate a count for each key number in the above code.
Eg: key- 574, it searches from pages 10-50 and increments the count.
The problem that I have is the count is continuous. After searching for the first key and moves on to the next key and then I need the count to start from the beginning rather than being continuous.
Eg: key-874 : count = 22, in my case the next key 875 : the count is 23
I need to make it 1.
I removed the if block and several lines because the code is too long.
Can someone please suggest me a way how to do it
Use an array for storing count values:
$count = array();
$numb=50;
foreach ($sepkeys as $dbkey)
{
for ($page=10;$page<=$numb;$page=$page + 10)
{
// the if block
$count[$dbkey] = $count[$dbkey] + 1;
}
}
//Displaying counts:
foreach($count as $key=>$val)
echo "Key {$key} has count: {$val}".PHP_EOL;
This way, every key value will have count stored in the array and you have separate count for separate keys.