I am using a foreach loop to run through an array. With it I have $q which iterates with a value of 1 on every loop run. And when the value reaches 1/3 of the total, it is to echo out new div, in order to make several columns.
But I cant seem to find the error.
$i = 0;
$count = count($segments->getItems());
$countdiv = $count / 3;
$countdiv = number_format((float)$countdiv,0,',','');
$q = 0;
foreach($segments->getItems() as $segment)
{
$q++;
$allusers = 0;
if($segment->getName() === 'All Users') {
$allusers = "checked";
}
?>
<label class="custom-control custom-checkbox">
<input type="checkbox" name="<?php echo $segment->getName();?>" value="segments[]" class="custom-control-input" <?php echo $allusers?>>
<span class="custom-control-indicator"></span>
<span class="custom-control-description"><?php echo $segment->getName();?></span>
</label>
<?php
if($q === $countdiv)
{
?>
</div>
</div>
<div class="col-md-6">
<div class="custom-controls-stacked">
<?php
}
}
number_format() returns a formatted string of the number. So when you then compare that string to an actual number using ===, it will always be false, since a string type can never be strictly equivalent to a number type. Also, it would only work the first time around as $q is always increasing.
As #Chris Forrence recommends you can do:
if(($q % round($count / 3)) === 0)
Let's dive into that a little bit. First we divide $count by 3 since we want three columns. We can't divide on a fraction of an item, so let's round that result to a whole number. We then use that to take the modulo (%) of $q. This just says divide x / y but instead of the result, give me the remainder. So each time that $q is a multiple of $count / 3 this will return 0. So, if we test that whole calculation to see if it equals 0 then we will know when we've hit one of our column boundaries.
If you're looping over a large amount of objects and performance becomes an issue, change your $countdiv declaration to be:
$countdiv = round($count / 3)
And then the above if statement can be cut down to:
if(($q % $countdiv) === 0)
Related
I got this where I want to display only one advertisement but randomly and it has more changes of displaying if the budget is higher. This is my code right now:
I already have the part where it calculates the percentage from 100% with alot of decimals but I'm lost in trying to display the advertisment with the percentage calculated and only show ONE advertisment.
If you have any questions or something like that, feel free to ask!
#php
$advertisment = DB::table('advertisment')
->orderBy('id', 'desc')
->get();
$totalbudget = 0;
$random = rand(100, 100000000000000);
$random1 = $random / 1000000000000;
echo $random1;
echo '<br><br>';
foreach ($advertisment as $ad) {
$total = $totalbudget + $ad->budget;
$totalbudget = $total;
}
// check what advertisment is the closest to the random number given
#endphp
I think I understand. If all of your advertisements have a budget, and your random1 represents a percent (1 - 100), you can try this in your existing function. It will also still calculate the total you were looking for, just use the Laravel sum() function on the collection. Note, I renamed the advertisement collection to plural for clarity.
$totalbudget = $advertisements->sum('budget');
$closest = null;
$closestAd = false
foreach ($advertisements as $ad) {
// first get percentage of total for this budget:
$thisPercent = ($ad->budget * 100) / $totalbudget;
if ($closest === null || abs($random1 - $closest) > abs($thisPercent - $random1)) {
$closest = $thisPercent;
$colsestAd = $ad;
}
}
At the end of the loop, you have both the percentage ($closest) and the ad itself ($closestAd) and the budget if you wish ($closestAd->budget).
There are a few unknowns, so this code may not work exactly. Please use it as a guide and tweak to get it working for you.
I have this array which links numbers to letters at the moment like this:
1-26 = A-Z
But there is more, 27=AA and 28=AB etc...
so basically when I do this:
var_dump($array[2]); //shows B
var_dump($array[29]); //shows AC
Now this array I made myself but it's becoming way too long. Is there a way to actually get this going on till lets say 32? I know there is chr but I dont think I can use this.
Is there an easier way to actually get this without using this way too long of an array?
It's slower calculating it this way, but you can take advantage of the fact that PHP lets you increment letters in the same way as numbers, Perl style:
function excelColumnRange($number) {
$character = 'A';
while ($number > 1) {
++$character;
--$number;
}
return $character;
}
var_dump(excelColumnRange(2));
var_dump(excelColumnRange(29));
here is the code which you are looking for :
<?php
$start = "A";
$max = 50;
$result = array();
for($i=1; $i<=$max; $i++) {
$result[$i] = $start++;
}
print_r($result);
?>
Ref: http://www.xpertdeveloper.com/2011/01/php-strings-unusual-behaviour/
This should work for you:
Even without any loops. First I calculate how many times the alphabet (26) goes into the number. With this I define how many times it has to str_repleat() A. Then I simply subtract this number and calculate the number in the alphabet with the number which is left.
<?php
function numberToLetter($number) {
$fullSets = (($num = floor(($number-1) / 26)) < 0 ? 0 : $num);
return str_repeat("A", $fullSets) . (($v = ($number-$fullSets*26)) > 0 ? chr($v+64) : "");
}
echo numberToLetter(53);
?>
output:
AAA
I am needing to add a different class at the end of every 4th item that I am looping through. I have done so by:
$i=0;
foreach($mount as $m){
$i++;
$startClass = '';
if($i==4||$i==8||$i==12){$startClass='<div with class>';} //adds class on 4th intervals
$ret.=''.$startClass.'<other HTML here and such>'; //shorted for readability
}
Now I'm sure there is a more appropriate way to handle this given the fact that if my loop contains 40 objects, I'll need to adjust the if statement accordingly.
I'm recalling an arithmetic formula that might work [an = a1+(n-1)d] but I'm finding that my idea seems off. I apply it (replacing an with i) and it will always = to the equation, thus each item gets the class.
Any suggestions? Thanks in advance!
Use the modulus operator
http://www.php.net/manual/en/language.operators.arithmetic.php
if(($i % 4) === 0){
//add class
}
what you are looking for is modulo operator
example:
if($i%4 == 0){$startClass='<div with class>';}
which means that i = k + 0, k being integer
A combination of the foreach control structure and the % modulus operator will give you what you need:
foreach ($mount as $key => $m) {
if ($key % 4 == 0) {
$startClass = '<div with class>';
} else {
$startClass = '';
}
$ret.=''.$startClass.'<other HTML here and such>';
}
The foreach hash-rocket (=>) notation enables you to pass the index of the current element being iterated through. You can use the index to keep track of the nth-object.
The modulus operator returns the remainder from division; if the remainder is zero, the divisor is a factor of the dividend and thus can be used to calculate nth-factors.
$i=0;
foreach($mount as $m)
{
if (($i++ % 4) == 0)
{
}
}
I have the following code:
<?php
$gender = array(
'Male'=>30,
'Female'=>50,
'U' =>20);
$total = array_sum(array_values($gender));
$current = 0;
$rand = rand(1,$total);
foreach ($gender as $key=>$value)
{
$current += $value;
if ($current > $rand)
{
echo $key;
}
}
?>
However, when I run it, I sometimes get:
MaleFemaleU
Or:
FemaleU
I set the values for the $gender arrays, and would like to generate the gender based on the percentage given, i.e. in this case: male 30, female 50, and unknown 20.
You need to stop looping when you display the variable.
foreach ($gender as $key=>$value)
{
$current += $value;
if ($current > $rand)
{
echo $key;
break; // Terminate the loop
}
}
That means that all those items are reaching the value needed to be echo'd but you aren't putting a line between then.
if($current > $rand) {
echo $key . "<br>";
}
Try that so they will display on a new line. From there we can work on the math.
rand will be a value within the range 1..100 since you're summing the values in the array. So then in the foreach loop you will print out all the values whenever `rand generates a value small enough to print out all the values.
For example, lets say $rand = 1, then $current will always be greater than $rand, since it can only as a lowest value have 20.
So, yeah, you most probably wan't to throw in a little break there.
Random thoughts
I'm a bit suspicious about the logic in this code however, will this give you a correct percentage? That is that 20% of the time when you run this the gender will be U, etc. ? Something looks fishy to me.
A better way of checking percentages (experimental) *
With the current solution I don't think you'll get the distribution of 20% U, 30% Male and 50% Female.
Since U has a lower percentage than Male and Female in your algorithm are greater than 20 the condition that would render U will always generate true for Male and Female also. Thus, with this algorithm you will never get the value U.
I suggest an easier approach by using ranges, that is for example 1-20 = U, 21-50 = Male and 51 - 100 = Female, the order is not important, just that the range equals the precentage. Then it's just a trivial matter of checking which range the rand is in.
Time to test your math skills...
I'm using php to find the average of $num1, $num2, $num3 and so on; upto an unset amount of numbers. It then saves that average to a database.
Next time the php script is called a new number is added to the mix.
Is there a math (most likely algebra) equation that I can use to find the average of the original numbers with the new number included. Or do I need to save the original numbers in the database so I can query them and re-calculate the entire bunch of numbers together?
array_sum($values) / count($values)
If what you mean by average is the 'mean' and you don't want to store all numbers then store their count:
$last_average = 100;
$total_numbers = 10;
$new_number = 54;
$new_average = (($last_average * $total_numbers) + $new_number) / ($total_numbers + 1);
Average = Sum / Number of values
Just store all 3 values, there's no need for anything complicated.
If you store the Average and Sum then calculate Number of values you'll lose a little accuracy due to truncation of Average.
If you store the Average and Number of values then calculate Sum you'll lose even more accuracy. You have more margin for error in calculating a correct value for Number of values than Sum thanks to it being an integer.
<?php
function avrg()
{
$count = func_num_args();
$args = func_get_args();
return (array_sum($args) / $count);
}
?>
http://php.net/manual/en/function.array-sum.php#101727
Thought that I should share my function
function avg(array $values) {
$sum = array_sum($values);
$count = count($values);
return ($count !== 0)? $sum / $count: NAN;
}
echo avg([1, 2, 3, 4]); // 2.5
Will return the average and also take into account 0, for example dividing by zero always returns NaN (Not a number)
1/0 = NaN
0/0 = NaN
If you know the amount of numbers you can calculate the old sum, add the new one and divide by the old amount plus one.
$oldsum = $average * $amount;
$newaverage = ($oldsum + $newnum) / ($amount + 1);
Typically what you might do is save two pieces of information:
the sum of all the numbers
the count of numbers
Whenever you want to get the average, divide the sum by the count (taking care for the case of count == 0, of course). Whenever you want to include a new number, add the new number to the sum and increment the count by 1.
This is called a 'running average' or 'moving average'.
If the database stores the average and the number of values averaged, it will be possible to calculate a new running average for each new value.
function avgvals($avg_vals,$avg_delimiter=',') {
if ( (is_string($avg_vals) && strlen($avg_vals) > 2) && (is_string($avg_delimiter) && !empty($avg_delimiter)) ) {
$average_vals = explode($avg_delimiter, $avg_vals);
$return_vals = ( array_sum($average_vals) / count($average_vals) );
} elseif ( (is_string($avg_vals) && strlen($avg_vals) <= 2) && (is_string($avg_delimiter) && !empty($avg_delimiter)) ) {
$return_vals = $avg_vals;
} else {
$return_vals = FALSE;
}
return $return_vals;
}
Code:
function avg($list){
$sum = array_sum($list);
$count = count($list);
return ($count)? $sum / $count: NAN;
}
print ("Average: ".avg([1,2,3,4,5]));
Output:
Average: 3
You need to save all the original numbers in the database.