Continue to next for loop if current loop is 0 - php

It seems this is a general question of programming logic, as this issue seems to arise in my code regardless of what language it's coded in.
Basically I have 2 nested for loops, inside a for loop. The purpose of these for loops is to enumerate all possible values between two sets of values.
The problem with the code is that is the second set of values contains a 0 the values won't enumerate.
Say for example we want to enumerate all values between 0,0,0 and 1,1,1, this works perfectly fine, as each nested loop is processed. However is we try to calculate between 0,0,0 and 0,1,0 the loop will not continue on to the next loop, instead it will exit the loop and continue on to the rest of the code.
for ($i1=$coords1[0]; $i1<=$coords2[0]; $i1++) { //if $coords2[0] = 0 loop will fail
for ($i2=$coords1[1]; $i2<=$coords2[1]; $i2++) { //if $coords2[1] = 0 loop will fail
for ($i3=$coords1[2]; $i3<=$coords2[2]; $i3++) {//if $coords2[2] = 0 loop will fail
$blocks.= $i1.",".$i2.",".$i3."|";
}
}
}
return $blocks;
Full code: PHPFIDDLE

Okay, to copy this over from our chat, I believe this is the solution:
<?php
$set1 = explode(",", '1,0,1');
$set2 = explode(",", '1,1,0');
$allbetween = _allbetween($set1, $set2);
echo 'All Between: '.$allbetween.'<br/>';
$allcount = count(explode("|", $allbetween))-1;
echo 'Number Of Blocks: '.$allcount;
function _allbetween($coords1, $coords2) {
$blocks = "";
for ($i=0; $i<=2; $i++) {
if ($coords1[$i] > $coords2[$i]) {
$tmp = $coords1[$i];
$coords1[$i] = $coords2[$i];
$coords2[$i] = $tmp;
}
}
for ($i1=$coords1[0]; $i1<=$coords2[0]; $i1++)
{
for ($i2=$coords1[1]; $i2<=$coords2[1]; $i2++)
{
for ($i3=$coords1[2]; $i3<=$coords2[2]; $i3++)
{
$blocks.= $i1.",".$i2.",".$i3."|";
}
}
}
return $blocks;
}
?>
DEMO HERE
The reason this works is that there is a swap loop at the beginning of your function, which swaps any of the three sets of values if the first is greater than the second. This ensures that all values "between" them can be calculated.
Edit: Fixing the demo link to the correct URL

the break; will do. see more information in the link:
http://www.php.net/manual/en/control-structures.break.php

Your loops will never loop as you are setting each initial value to the end range value. Instead use:
for ($i1=0; $i1<=$coords2[0]; $i1++)
...
etc
In terms of fall-through, try the following:
for ($i1=0; $i1<=$coords2[0] + 1; $i1++)
...
etc

Here's the problem: Dumping out your two $coords arrays:
$coords1:
array(3) {
[0]=>
string(1) "0"
[1]=>
string(1) "0"
[2]=>
string(1) "1"
}
$coords2:
array(3) {
[0]=>
string(1) "1"
[1]=>
string(1) "0"
[2]=>
string(1) "1"
}
On your first iteration:
$coords1[0] => 1
$coords2[0] => 0
1 <= 0 -> FALSE
so your outermost loop NEVER executes at all.

I think you are searching for
GOTO function
And for the
Continue function

Related

array_uintersect with sub-arrays doesn't intersect first item

I have created the following script for creating an array_uintersect alogrithm.
function compare2D($topic, $nomination): int
{
if (is_array($nomination)) {
return in_array($topic, $nomination) ? 0 : 1;
}
else if (is_array($topic)) {
return in_array($nomination, $topic) ? 0 : 1;
}
return strcmp($topic, $nomination);
}
$arr = [['REMOTE', 'REMOTE_PREMIUM'], 'SECURE'];
$topic = ['SECURE', 'REMOTE'];
var_dump(array_uintersect($topic, $arr, 'compare2D'));
When I run it, the result is
array(1) {
[0] =>
string(6) "SECURE"
}
Where it should be returning
array(2) {
[0] =>
string(6) "SECURE"
[1] =>
string(6) "REMOTE"
}
I found that this is only dependent on the array in 2nd argument to _uintersect having a sub-array at index 0 (first item).
When I move the sub-array to any position except for the 1st, i.e:
$arr = ['SECURE', ['REMOTE', 'REMOTE_PREMIUM']];
// or
$arr = ['SOMEVALUE', ['REMOTE', 'REMOTE_PREMIUM'], 'SECURE'];
...the intersection works fine, and I get the intended result above.
Does anyone know some algorithmic rules of php intersection that I am not aware of?
I think you can switch the logic of returning 1 and 0, so return 1 when the value is in the array as you want to find the intersection.
For the last part, using strcmp will return 0 if the strings are equal. In that case you can check if they are equal, and if they are, then return 1.
function compare2D($topic, $nomination): int
{
if (is_array($nomination)) {
return in_array($topic, $nomination) ? 1 : 0;
}
if (is_array($topic)) {
return in_array($nomination, $topic) ? 1 : 0;
}
return strcmp($topic, $nomination) === 0 ? 1 : 0;
}
$topic = ['SECURE', 'REMOTE'];
$arr = [['REMOTE', 'REMOTE_PREMIUM'], 'SECURE'];
$res = array_uintersect($topic, $arr, 'compare2D');
var_dump($res);
Output
array(2) {
[0]=>
string(6) "SECURE"
[1]=>
string(6) "REMOTE"
}
Php demo | Php demo with more nested arrays

Changing values of multidimensional array php

Its my first time working with multidimensional arrays in php. I need to change the second number in each sub array.
What I want is to check if the Id in the array matches the Id from the database. When the two match I want to change the 2nd entry in the sub array by adding a number to it. If the Id from the query does not match anything in the list I want a new sub array to be pushed to the end of the array with the values of Id and points_description.
Also, if its helpful, my program right now does find the matches. The only thing is, it does not update the 2D array.
$array = array(array());
while ($row_description = mysqli_fetch_array($query_description)) {
$check = 1;
$is_match = 0;
foreach ($array as $i) {
foreach ($i as $value) {
if ($check == 1) {
if ($row_description['Id'] == $value) {
//$array[$i] += $points_description;
$is_match = 1;
}
}
$check++;
$check %= 2; //toggle between check and points
}
}
if ($is_match == 0) {
array_push($array, array($row_description['Id'], $points_description));
}
}
I feel like Im doing this so wrong. I just want to go through my 2D array and change every second value. The expected output should be a print out of all the Ids and their corresponding point value
I hope this is helpful enough.
Example: $row_description['Id'] = 2 and $array = array(array(2,1), array(5,1) , array(6,1))
output should be $array = array(array(2,4), array(5,1) , array(6,1))
if $row_description['Id'] = 3 and $array = array(array(2,1), array(5,1) , array(6,1))
output should be $array = array(array(2,4), array(5,1) , array(6,1),array(3,3))
By default PHP will copy an array when you use it in a foreach.
To prevent PHP from creating this copy you need to use to reference the value with &
Simple example :
<?php
$arrFoo = [1, 2, 3, 4, 5,];
$arrBar = [3, 6, 9,];
Default PHP behavior : Make a copy
foreach($arrFoo as $value_foo) {
foreach($arrBar as $value_bar) {
$value_foo *= $value_bar;
}
}
var_dump($arrFoo);
/* Output :
array(5) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
[4]=>
int(5)
}
*/
ByReference : Don't create the copy :
foreach($arrFoo as &$value_foo) {
foreach($arrBar as $value_bar) {
$value_foo *= $value_bar;
}
}
var_dump($arrFoo);
/* Output :
array(5) {
[0]=>
int(162)
[1]=>
int(324)
[2]=>
int(486)
[3]=>
int(648)
[4]=>
&int(810)
}
*/

php - use array variable outside for loop

I have this PHP code, with a for loop:
$expireData = array();
for($x = 0; $x <= 10; $x++){
$stmt=$dbh->prepare("select round((expire - unix_timestamp()) / 86400) as days, count(*) as cnt from users WHERE user_by=:username group by days;");
$stmt->bindParam(":username",$userdata['username']);
$stmt->execute();
$row = $stmt->fetchAll();
#var_dump($row);
if($row["cnt"] > 0){
$expireData[] = $row["cnt"];
}else{
$expireData[] = 0;
}
}
If I do the var_dump($row) I get:
array(2) {
[0]=>
array(4) {
["days"]=>
string(2) "27"
[0]=>
string(2) "27"
["cnt"]=>
string(1) "2"
[1]=>
string(1) "2"
}
[1]=>
array(4) {
["days"]=>
string(3) "116"
[0]=>
string(3) "116"
["cnt"]=>
string(1) "8"
[1]=>
string(1) "8"
}
}
But if I just echo $row['cnt']; it doesn't echo anything out - it's empty. Why?
Ultimately, I wish to use the data from the for loop outside the for loop - like:
echo implode(',', $expireData);
But that just gives me
0,0,0,0,0,0,0,0,0,0
What am I doing wrong?
Because you're using fetchAll() to retrieve all rows into $row, its contents are a 2 dimensional array representing multiple rows. So the key ['cnt'] is present, but is one dimension farther in your array.
$row['cnt'] doesn't exist but $row[0]['cnt'] does and $row[1]['cnt'] do exist.
The simplest solution with your current code is to move the $expireData handling outside the loop and into a loop of its own:
$expireData = array();
$stmt=$dbh->prepare("select round((expire - unix_timestamp()) / 86400) as days, count(*) as cnt from users WHERE user_by=:username group by days;");
$stmt->bindParam(":username",$userdata['username']);
$stmt->execute();
// Load all rows into $rows rather than $row...
$rows = $stmt->fetchAll();
// Loop over all rows to populate $expireData
foreach ($rows as $row) {
if ($row["cnt"] > 0){
$expireData[] = $row["cnt"];
}else{
$expireData[] = 0;
}
}
print_r($expireData);
The other method would be to switch from fetchAll() to plain fetch() and append rows onto $rows in a while loop:
// Array to hold all rows
$rows = array();
// (The outer for loop is removed...)
$stmt=$dbh->prepare("select round((expire - unix_timestamp()) / 86400) as days, count(*) as cnt from users WHERE user_by=:username group by days;");
$stmt->bindParam(":username",$userdata['username']);
$stmt->execute();
// Perform single fetch() calls in a while loop
while ($row = $stmt->fetch()) {
// Append onto array of all rows
$rows[] = $row;
// Then handle $expireData in the same loop
if ($row["cnt"] > 0){
$expireData[] = $row["cnt"];
}else{
$expireData[] = 0;
}
}
Pad the array to 10 values:
As determined in the comments, you need your final $expireData array to have 10 values. Rather than doing that with a loop, use array_pad() to extend it to ten and fill it with zeros.
$expireData = array_pad($expireData, 10, 0);
// turns [2,8] into [2,8,0,0,0,0,0,0,0,0]
Notes on the for loop:
The use of the outer for look is suspect because it is apparently executing the same statement each time. That loop may be entirely unneeded, and all you need is its body.
Notes on error reporting:
The fact that you did not see PHP complaining about undefined index 'cnt' while loading the loop suggests that you are not developing with display_errors turned on and error_reporting turned up. Always do so when developing and testing code. It may have helped you see the problem sooner.
At the top of your script:
error_reporting(E_ALL);
ini_set('display_errors', 1);

Look for duplicate values in a associative array and add them to a count

Hi I am trying to count the number of duplicate values in a associative array that looks like this:
array(3) { [0]=> array(3) { ["Title"]=> string(25) "hello"
["Price"]=> int(50)
["Count"]=> int(1) }
[1]=> array(3) { ["Title"]=> string(35) "world"
["Price"]=> int(50)
["Count"]=> int(1) }
[2]=> array(3) { ["Title"]=> string(25) "hello"
["Price"]=> int(50)
["Count"]=> int(1) } }
As you can see here there is a duplicate value in the "Title" lable I want to count them and add one to the "Count" part. I started to do something like this:
$prodArray = array();
// Add the values to the array if it's the first time it occurs.
if (!in_array($row['prodTitle'], $prodArray["Title"]))
{
array_push($prodArray,
array( Title => $row['prodTitle'],
Price => $row['prodPrice'],
Count => 1)
);
}
else
{
//Add one to the count for the current item.
}
the thing is I can't access the "Title" element in the array through the in_array function. Any suggestions are welcome.
If you want to detect dups in an array that you are creating, something like this avoid having to go through the array multiple times:
$arr=array();
while($row = mysql_fetch_array($result)) {
$arr[$row['prodTitle']] = isset($arr[$row['prodTitle']])
? $arr[$row['prodTitle']] +1
: 0;
}
$dups = array_keys(array_filter($arr)); //any key => 0 will be filtred out
If you want to just get the dups directly by SQL, have a look at this:
Your current query--
SELECT prodTitle
FROM product
WHERE prodTitle != '{$keyword}'
AND creditCard IN( SELECT creditCard FROM product WHERE prodTitle ='{$keyword}');
which given data like this
prod cc
A 1
A 2
A 3
A 1
A 1
B 15
B 1
B 2
B 21
C 10
C 1
returns this set (with $keyword=='A'):
prod
B
B
C
An aggregate query that returns only records where credit cards used on non-X were also used on X at least twice --
SELECT p1.prodTitle, COUNT(p2.creditCard) AS numrecords
FROM product p1
JOIN product p2
ON (p1.creditCard = p2.creditCard)
WHERE p1.prodTitle != '{$keyword}'
AND p2.prodTitle = '{$keyword}'
GROUP BY p1.prodTitle
HAVING COUNT(p2.creditCard) > 1;
given the same data, returns this set:
prod num
B 2
Doing an aggregate query avoids all the messing about with loops. Here's a link to the MySQL list of aggregate functions.
Okey so I found my solution and I made it look something like this probably not he most efficient way but it works:
$prodArray = array();
$ar = array();
$query ="THE QUERY";
$result = mysql_query($query) or die(mysql_error());
while($row = mysql_fetch_array($result))
{
array_push($ar, $row['prodTitle']);
}
function findDuplicates($data,$dupval) {
$nb= 0;
foreach($data as $key => $val)
if ($val==$dupval) $nb++;
return $nb;
}
$uniarr = array_unique($ar);
//Will run the function findDuplicates for each unique title in the array
for ($i = 0; $i < sizeof($uniarr); $i++)
{
$count = findDuplicates($ar, $uniarr[$i]);
array_push($prodArray, array( Title => $uniarr[$i], Count => $count));
}
//Displays 2 of the results in the array
for ($c = 0; $c < 2; $c++)
{
echo "The title:".$prodArray[$c]["Title"]." And the amount:".$prodArray[$c]["Count"];
echo "<br />";
}
So that's pretty much it feel free to post your comments on this and if you have any improvements feel free to post them.

Random But Unique Pairings, with Conditions

I need some help/direction in setting up a PHP script to randomly pair up items in an array.
The items should be randomly paired up each time.
The items should not match themselves ( item1-1 should not pair up with item1-1 )
Most of the items have a mate (ie. item1-1 and item1-2). The items should not be paired with their mate.
I've been playing around with the second script in this post but, I haven't been able to make any progress. Any help is appreciated.
Very simple approach, but hopefully helpful to you:
(mates, if grouped in an array (e.g. array('a1', 'a2')), will not be paired.)
function matchUp($array) {
$result = array();
while($el = array_pop($array)) {
shuffle($array);
if (sizeof($array) > 0) {
$candidate = array_pop($array);
$result[] = array(
array_pop($el),
array_pop($candidate)
);
if (sizeof($el) > 0) {
$array[] = $el;
}
if (sizeof($candidate) > 0) {
$array[] = $candidate;
}
}
else {
$result[] = array(array_pop($el));
}
}
return $result;
}
$array = array(
array('a1', 'a2'),
array('b1', 'b2'),
array('c1'),
array('d1'),
array('e1', 'e2'),
array('f1'),
array('g1', 'g2'),
);
Update:
foreach(matchUp($array) as $pair) {
list($a, $b) = $pair + array(null, null);
echo '<div style="border: solid 1px #000000;">' . $a . ' + ' . $b . '</div>';
}
With the randomness, there is no guarantee that a full correct solution will be reached.
Certain problem sets are more likely to be solved than others. Some will be impossible.
You can configure how many times it will try to achieve a good solution. After the specified number of tries it will return the best solution it could find.
function pairUp (array $subjectArray) {
// Config options
$tries = 50;
// Variables
$bestPaired = array();
$bestUnpaired = array();
for($try = 1; $try <= 50; $try++) {
$paired = array();
$unpaired = array();
$toBePaired = $subjectArray;
foreach($subjectArray as $subjectIndex => $subjectValue) {
// Create array without $thisValue anywhere, from the unpaired items
$cleanArray = array();
foreach($toBePaired as $index => $value) {
if($value != $subjectValue) {
array_push($cleanArray, array(
'index' => $index,
'value' => $value
));
}
}
sort($cleanArray); // reset indexes in array
// See if we have any different values left to match
if(count($cleanArray) == 0) {
array_push($unpaired, $subjectValue);
continue;
}
// Get a random item from the clean array
$randomIndex = rand(0,count($cleanArray)-1);
// Store this pair
$paired[$subjectIndex] = $subjectValue . '-' . $cleanArray[$randomIndex]['value'];
// This item has been paired, remove it from unpairedItems
unset($toBePaired[$cleanArray[$randomIndex]['index']]);
sort($toBePaired);
}
// Decide if this is our best try
if(count($paired) > count($bestPaired)) {
$bestPaired = $paired;
$bestUnpaired = $unpaired;
}
// If we had no failures, this was a perfect try - finish
if(count($unpaired) == 0) { $break; }
}
// We're done, send our array of pairs back.
return array(
'paired' => $bestPaired,
'unpaired' => $bestUnpaired
);
}
var_dump(pairUp(array('a','b','c','d','e','a','b','c','d','e')));
/*
Example output:
array(2) {
["paired"]=>
array(10) {
[0]=>
string(3) "a-b"
[1]=>
string(3) "b-c"
[2]=>
string(3) "c-d"
[3]=>
string(3) "d-e"
[4]=>
string(3) "e-a"
[5]=>
string(3) "a-b"
[6]=>
string(3) "b-e"
[7]=>
string(3) "c-d"
[8]=>
string(3) "d-c"
[9]=>
string(3) "e-a"
}
["unpaired"]=>
array(0) {
}
}
*/
Case 1: if all elements had a mate
If all elements had a mate, the following solution would work, although I don't know if it would be perfectly random (as in, all possible outputs having the same probability):
Shuffle the list of elements, keeping mates together
original list = (a1,a2),(b1,b2),(c1,c2),(d1,d2)
shuffled = (c1,c2),(d1,d2),(a1,a2),(b1,b2)
Shift the second mate to the right. The matches have been formed.
shifted = (c1,b2),(d1,c2),(a1,d2),(b1,a2)
(Edit1: if applied exactly as described, there is no way a1 ends up matched with b1. So, before shifting, you may want to throw a coin for each pair of mates to decide whether they should change their order or not.)
Case 2: if only some elements have a mate
Since in your question only some elements will have a mate, I guess one could come up with the following:
Arbitrarily pair up those elements who don't have a mate. There should be an even number of such elements. Otherwise, the total number of elements would be odd, so no matching could be done in the first place.
original list = (a1,a2),(b1,b2),c1,d1,e1,f1 // c1,d1,e1 and f1 don't have mates
list2 = (a1,a2),(b1,b2),(c1,d1),(e1,f1) // pair them up
Shuffle and shift as in case 1 to form the matches.
shuffled = (e1,f1),(a1,a2),(c1,d1),(b1,b2)
shifted = (e1,b2),(a1,f1),(c1,a2),(b1,d1)
Again, I don't know if this is perfectly random, but I think it should work.
(Edit2: simplified the solution)
(Edit3: if the total number of elements is odd, someone will be left without a match, so pick an element randomly at the beginning to leave it out and then apply the algorithm above).

Categories