maintaining a count in foreach - php

$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.

Related

How to print a 2d spiral matrix in counter clockwise using php [duplicate]

I want to print an array in spiral order. For arrays with sizes 3x3, 4x4, ...etc. my code works correctly, but for 3x5, 4x6 or 5x8 sizes the output is wrong, returning only the first iteration.
This is my simple code:
private function _spiral($rows, $cols, array $array) {
$offset = 0;
while($offset < ($rows - 1)){
for($col = $offset; $col <= $cols - 1; $col++){
print($array[$offset][$col] . ' ');
}
$offset++;
$cols--;
for($row = $offset; $row < $rows; $row++){
print($array[$row][$cols] . ' ');
}
$rows--;
for($col = $cols - 1; $col >= $offset; $col--){
print($array[$rows][$col] . ' ');
}
for($row = $rows; $row >= $offset; $row--){
print($array[$row][$offset - 1] . ' ');
}
}
}
Example with 3 rows and 4 columns:
$array = array(
array(00,01,02,03),
array(10,11,12,13),
array(20,21,22,23)
)
Expected result for this array is 0 1 2 3 13 23 22 21 20 10 11 12, but the output of my function stops after 10.
For 4 rows and 4 columns:
$array = array(
array(00,01,02,03),
array(10,11,12,13),
array(20,21,22,23),
array(30,31,32,33)
)
...it should return 0 1 2 3 13 23 33 32 31 30 20 10 11 12 22 21, and that is what my code returns.
But I want both cases to work with my code. How can I correct the code to also produce the correct output for the first, and other cases?
There are a few problems with your code:
it does not treat the four directions of traversal in the same way. You have four loops for these four directions, but in some you have <= as loop-end condition in others <, in some the condition is on something minus 1, in others not.
it has no provision for when all elements have been printed by the first or second inner loop, and thus the remaining loops will in some cases print already printed elements.
the outer loop condition does not check whether there are still columns that need traversal. It is not enough to test for such rows only.
Although you could try to fix your code, I think it is better to start from scratch, taking into account that the solution should be symmetric for all four directions. This is an important intuitive reaction to develop: spot symmetries. This will lead to less code and fewer bugs.
You want to traverse a dimension (row or column) in your array until you reach the border of the array or an element you already printed. Then you want to turn 90° to the right and repeat exactly the same logic over and over again. So if your code looks different for these different directions, something is not right.
I will share two implementations. Both will use the concept of the "current" cell, and let it move around in spiral motion.
The first solution treats going back or forward along a row with the same code, and similarly it has one piece of code for traversing a column forward or backward. So this solution has two inner loops, one for traversing along a row, and another for traversing along a column. The direction in which a row or column is traversed is kept in the $direction variable, which flips between 1 and -1 at each execution of the outer loop:
function _spiral(array $array) {
// No need to have the number of rows and columns passed as arguments:
// We can get that information from the array:
$rows = count($array);
$cols = count($array[0]);
// Set "current" cell to be outside array: it moves into it in first inner loop
$row = 0;
$col = -1;
$direction = 1; // Can be 1 for forward and -1 for backward
while ($rows > 0 and $cols > 0) {
// Print cells along one row
for ($step = 0; $step < $cols; $step++) {
$col += $direction;
print $array[$row][$col] . ' ';
}
// As we have printed a row, we have fewer rows left to print from:
$rows--;
// Print cells along one column
for ($step = 0; $step < $rows; $step++) {
$row += $direction;
print $array[$row][$col] . ' ';
}
// As we have printed a column, we have fewer columns left to print from:
$cols--;
// Now flip the direction between forward and backward
$direction = -$direction;
}
}
Note the perfect symmetry between the first inner loop and the second inner loop.
In a second solution, this use of symmetry is taken one step further, in order to replace the two inner loops with only one. For that to happen we must abandon the use of separate variables for rows and columns, and use the concept of a size related to a dimension:
function _spiral(array $array) {
// This version of the function aims to treat rows and columns in the same way,
// They are just another dimension, but all the logic is exactly the same:
// $size[] has the number of rows in $size[0] and number of columns in $size[1]
$size = Array(count($array), count($array[0]));
// $current[] has the current row in $current[0] and current column in $current[1]
$current = Array(0, -1);
// $direction[] has the current row-traversal direction in $direction[0]
// and column-traveral direction in $direction[1]
$direction = Array(1, 1);
$dimension = 0; // Which dimension to traverse along, can be 0 for row, 1 for column
while ($size[$dimension] > 0) {
// Switch dimension (row to column, column to row), to traverse along
$dimension = 1 - $dimension;
// Print one line along that dimension, in its current direction
for ($step = 0; $step < $size[$dimension]; $step++) {
$current[$dimension] += $direction[$dimension];
print $array[$current[0]][$current[1]] . ' ';
}
// As we have printed a line, we have fewer left to print from:
$size[1 - $dimension]--;
// Now flip the direction between forward and backward for this dimension:
$direction[$dimension] = -$direction[$dimension];
}
}
An extended version
Upon request more than one year later: here is a version that allows one to choose the corner to start from, and whether to do it counter-clockwise instead of clockwise. This function will not print the result, but return a 1D array, with the spiral sequence. This way you can decide yourself what to do with the result: print it, or ... whatever.
function spiral(array $array, $startRight = false, $startBottom = false,
$counterClockWise = false) {
// This version allows to select which corner to start from, and in which direction.
// $size[] has the number of rows in $size[0] and number of columns in $size[1]
$size = [count($array), count($array[0])];
// $direction[] has the current row-traversal direction in $direction[0]
// and column-traversal direction in $direction[1]
$direction = [$startBottom ? -1 : 1, $startRight ? -1 : 1];
// Which dimension to traverse along: false means row, true means column.
// Every one of the optional arguments will flip the first dimension to use:
$dimension = ($startBottom xor $startRight xor $counterClockWise);
// $current[] has the current row in $current[0] and current column in $current[1]
$current = [$startBottom * (count($array)-1), $startRight * (count($array[0])-1)];
// Go back one step, outside of the grid
$current[!$dimension] -= $direction[!$dimension];
while ($size[$dimension] > 0) {
// Switch dimension (row to column, column to row), to traverse along
$dimension = !$dimension;
// Print one line along that dimension, in its current direction
for ($step = 0; $step < $size[$dimension]; $step++) {
$current[$dimension] += $direction[$dimension];
$result[] = $array[$current[0]][$current[1]]; // store in new array
}
// As we have printed a line, we have fewer left to print from:
$size[!$dimension]--;
// Now flip the direction between forward and backward for this dimension:
$direction[$dimension] = -$direction[$dimension];
}
return $result; // Return the resulting spiral as a 1D array
}
See it run on eval.in

How to make comparisons of a needle in a haystack more efficient

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++;
}
}
}

WordPress Loop to dynamically close Bootstrap rows

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.

PHP Function 'overloops' array returns multiple instances of same object

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

Adding data from an array to a new array

I have created an array of data, from which I can loop through specific fields and echo these values out, but what I need to do is add these values to a new array, ultimately allowing me to find the average of the values in the new array. As i've said, I can echo out the data, and I think I've figured how to get the average, if only I can create the new array! Any help would be greatly appreciated as I just can't find the answer anywhere, and I'm running low on talent!
My table contains approx 25 fields, im pulling out a number of rows based on a session variable. In the instance im working on, I need to take just the values from 1 column in the table, and add these to an array. The code below will loop through the values, and echo them out, 1 at a time:-
while ($cdarray=mysql_fetch_array($calldata)) {
echo $cdarray['score_total'];
}
This gives me 25555 which are the 4 values I would expect 25, 5, 5, 5
I've tried
while ($cdarray=mysql_fetch_array($calldata)) {
$cdts = $cdarray['score_total'];
$cdtsar = array($cdts);
}
Which results in $cdts being assigned a value of 5,
Any help greatly appreciated!!
This will get your data from the array, place it into a new one and calculates the average.
$cdtsar = array();
while ($cdarray=mysql_fetch_array($calldata)) {
$cdtsar[] = $cdarray['score_total'];
}
$average = array_sum($cdtsar) / count($cdtsar);
It actually prints 25 and 5 and 5 and 5, but there are no spaces in between so it looks like "25555". To verify this yourself:
while ($cdarray=mysql_fetch_array($calldata)) {
echo $cdarray['score_total'];
echo " / ";
}
To get the average, you can either use
$sum = $count = 0;
$average = null;
while ($cdarray=mysql_fetch_array($calldata)) {
$sum += $cdarray['score_total'];
++$count;
}
// Make sure to guard against divide by zero
if ($count) {
$average = $sum / $count;
}
or you might have the database calculate the average for you, if changing the query is an option.
If you want to assign the elements to the new array use like this
$cdtsar = array();
while ($cdarray=mysql_fetch_array($calldata)) {
array_push($cdtsar,$cdarray['score_total']);
}
To find the average of the array
$sum = array_sum($cdtsar);
$num = sizeof($cdtsar);
$avg = $sum/$num;
echo $avg;

Categories