Nested Foreach() PHP - php

I need some assistance with my code logic:
The expected output of the following code is 1110, how to achieve that value?
<?php
$user_accepted_events = [1,2,3];
$all_events = [1,2,3,4];
//Nested foreach loop for testing if the user accepted an event
foreach ($all_events as $single_row) {
foreach ($user_accepted_events as $user_single_id) {
if ($single_row == $user_single_id) { //This prints expected value
print_r("1"); //User has accepted event
} else { //Here it logically print's 0 nine times
print_r("0"); //User has not accepted Event
}
}
}
//Expected Output is 1110
//Real Output is 100010001000
?>
Thanks.

As you have nested loops - it will compare each item against every nested item and most of them won't match - producing multiple results for each item.
Instead - use in_array() to check each item...
foreach ($all_events as $single_row) {
if ( in_array($single_row, $user_accepted_events)) {
print_r("1"); //User has accepted event
} else {
print_r("0"); //User has not accepted Event
}
}

You've got a logical error in your code: you are printing 1 or 0 for every permutation of both loops.
As there are 4 items in the outer loop and 3 in the inner, you are receiving 12 outputs.
Instead, keeping the same approach you have already adopted, you can capture whether the user has attended the event in a variable, and break if so.
Then once for each of the outer loops, output the result:
$user_accepted_events = [1,2,3];
$all_events = [1,2,3,4];
foreach ($all_events as $single_row) {
$hasAccepted = false;
foreach ($user_accepted_events as $user_single_id) {
if ($single_row == $user_single_id) {
$hasAccepted = true;
break;
}
}
print_r($hasAccepted ? 1 : 0);
}
Output:
1110

Related

How to track if a variable value is used multiple times in same php while loop

I found this snippet in a different question and answer, and it detects if a variable value is the same as the variable value in the previous loop.
$prevValue = NULL;
while(condition) {
if ($curValue == $prevValue) {
//do stuff
}
$prevValue = $curValue;
}
However what I want to do is to check if a variable value has been used before in the loop, but anywhere in the loop, so if the value happened 1 or 2 or 10 loops ago I want it to tell me if the variable value has come through the loop before.
Make an array of previouse values and test by in_array function
$prevValue = [];
while(condition) {
if (in_array($curValue, $prevValue)) {
//do stuff
}
$prevValue[] = $curValue;
}
Use an array to store each value and then check if the current value is in the array:
$prevValues = array();
while(/*condition*/) {
if (in_array($curValue, $prevValues)) {
//do stuff
}
$prevValues[] = $curValue;
}
As Marc B points out in a comment, you can do it this way as well. It might be marginally faster but I haven't tested it:
while(/*condition*/) {
if (isset($prevValues[$curValue])) {
//do stuff
}
$prevValues[$curValue] = 1; //set to whatever
}
If you just want to print out unique values, use array_unique.
Here is an example:
//This should output 2 3 1 4
$arr = array(2, 3, 2, 1, 4, 4);
foreach(array_unique($arr) as $value){
echo $value;
}

(Why) should I test if an array is empty prior to a for loop?

Given an empty array $items = array();
Why should I use the following code (which I've seen used before):
if (count($items) > 0) {
foreach ($items as $item) // do stuff here
}
instead of just
foreach ($items as $item) // do stuff here
If count($items) === 0 the loop won't execute anyway??
You don't generally need to do the check. I see lots of code with that check, but it's often unnecessary, and I think it's usually due to ignorance on the part of the programmer. A similar pattern that I frequently see is after database queries:
if (mysqli_num_rows($stmt) > 0) {
while ($row = mysqli_fetch_assoc($stmt)) {
...
}
}
This test is also unnecessary; if no rows were found, the first fetch will return false, and the loop will stop.
The only case where it's useful is if you want to tell the user that there were no results, instead of just displaying an empty table. So you might do:
if (count($items) > 0) {
echo "<table>";
foreach ($items as $item) {
// display table row
}
echo "</table>";
} else {
echo "<b>No data found!</b>";
}
It actually depends on what you want to do. As the comments have pointed out, you may want an empty array to be a special case, so you'd like to handle that case differently. Otherwise, no warning will be thrown if you execute foreach on an empty array, you just won't get any results. A typical check you should execute is if $items is an array at all, or cast $items into an array anyway to avoid getting that warning. If you did that and $items would be generally be converted into an array of one value, i.e. the value $items had at that point.
e.g.
$items = 2;
foreach((array)$items as $item) {
print $item; //will print 2 alright
}
or
if(is_array($items)) {
foreach($items as $item) {
print $item;
}
}
else {
// do something here
}

How can I run 2 loops together in PHP without duplicating values?

I'm trying to check MD5 of some data with md5 some files, both of them are stored in one dimensional arrays. Say I have 4 files in the $files array with the same number of $datas, the following code prints "NO DIFFERENCE" 12 times instead of 4 times.
foreach($files as $file) {
foreach($datas as $data) {
if(md5($data) !== md5_file($file)) {
echo "NO DIFFERENCE";
}
}
}
How do I prevent duplicating a loop?
Update:
Both arrays $datas and $files contains equal number of values but the tricky part is the values in $files array starts from key number 2 (because I removed "." and ".." from scandir result) whereas in $datas array values start from key number 0.
the following code prints "NO DIFFERENCE" 12 times instead of 4 times.
The reason for that is you have a nested loop.
For each value in the $files array, your inner foreach will run once.
So say if you have 3 values in $files and 4 values in $datas, the loop will run as follows:
First value in $files iterated
Inner loop runs, and iterates through all 4 values in $datas
Second value in $files iterated
Inner loop runs, and iterates through all 4 values in $datas
Third value in $files iterated
Inner loop runs, and iterates through all 4 values in $datas
Try this with one loop like this :
foreach($datas as $key => $value) {
if(md5($value) !== md5_file($files[$key])) {
echo "NO DIFFERENCE";
}
}
Note: The loop work when you have same no of values for both arrays
If you want to compare md5(files) to the mfs5(datas) you can simply do this:
for ($i = 0; $i < sizeof($files); $i++){
if(md5($datas[$i]) !== md5_file($files[$i+2]))
echo "NO DIFFERENCE";
}
If you want to check if each file have one corresponding md5(datas) then you should use you double loop as you did.
First, are you sure that !== is the operator you want to use to say 'no difference' ?
If you are looking for equality, maybe you want to use ===
Second, md5(...) is time consuming, so extract the hash in a variable.
Third, if you mean equality, you can add a break in the inner loop to stop looping as soon as you find the equality.
foreach($files as $file) {
$md5File = md5_file($file); // extract in a variable
foreach($datas as $data) {
if(md5($data) === $md5File) { // === instead of !==
echo "NO DIFFERENCE";
break; // break as soon as possible
}
}
}
You could use a callback function. But then you should be clear about how exactly you will describe an algorithm of your problem.
The following sample shows how to maybe achieve it. But it assumes that the arrays are in the same order and that you don't want to cross-compare everything. Also array_udiff may not be the best approach for it.
function compare_by_md5($data, $file) {
if( md5($data) === md5_file($file)) {
echo "NO DIFFERENCE";
}
}
array_udiff($datas, $files, 'compare_by_md5');
Sample is shown here: http://codepad.org/lYOyCuXA
If you simply want to detect if there is a difference:
$dataHashes = array();
foreach($datas as $data) {
$dataHashes[md5($data)] = true;
}
$different = false;
foreach($files as $file) {
if(!isset($dataHashes[md5_file($file)])) {
$different = true;
break;
}
}
var_dump($different);
If you want to know which files are different, then:
$dataHashes = array();
foreach($datas as $data) {
$dataHashes[md5($data)] = true;
}
foreach($files as $file) {
if(!isset($dataHashes[md5_file($file)])) {
echo $file, 'is different', PHP_EOL;
}
}

PHP Go to the next element of array

I have created an array list with the following code:
<?php
$ids = array();
if (mysql_num_rows($query1))
{
while ($result = mysql_fetch_assoc($query1))
{
$ids["{$result['user_id']}"] = $result;
}
}
mysql_free_result($query1);
?>
Now, i need to read two elements from the array. The first is the current and the second one is the next element of array. So, the simplified process is the following:
i=0: current_element (pos:0), next_element (pos:1)
i=1: current_element (pos:1), next_element (pos:2)
etc
To do this, i have already written the following code, but i cant get the next element for each loop!
Here is the code:
if (count($ids))
{
foreach ($ids AS $id => $data)
{
$userA=$data['user_id'];
$userB=next($data['user_id']);
}
}
The message i receive is: Warning: next() expects parameter 1 to be array, string given in array.php on line X
Does anyone can help? Maybe i try to do it wrongly.
The current, next, prev, end functions work with the array itself and place a position mark on the array. If you want to use the next function, perhaps this is the code:
if (is_array($ids))
{
while(next($ids) !== FALSE) // make sure you still got a next element
{
prev($ids); // move flag back because invoking 'next()' above moved the flag forward
$userA = current($ids); // store the current element
next($ids); // move flag to next element
$userB = current($ids); // store the current element
echo(' userA='.$userA['user_id']);
echo('; userB='.$userB['user_id']);
echo("<br/>");
}
}
You'll get this text on the screen:
userA=1; userB=2
userA=2; userB=3
userA=3; userB=4
userA=4; userB=5
userA=5; userB=6
userA=6; userB=7
userA=7; userB=8
You get the first item, then loop over the rest and at the end of each loop you move the current item as the next first item ... the code should explain it better:
if (false !== ($userA = current($ids))) {
while (false !== ($userB = next($ids))) {
// do stuff with $userA['user_id'] and $userB['user_id']
$userA = $userB;
}
}
Previous answer
You can chunk the arrays into pairs:
foreach (array_chunk($ids, 2) as $pair) {
$userA = $pair[0]['user_id']
$userB = $pair[1]['user_id']; // may not exist if $ids size is uneven
}
See also: array_chunk()

PHP - Count all elements of an Array that Satisfy a Condition [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Search for PHP array element containing string
I've created a mysql query that pulls through several products, all with the following information:
Product ID
Product Name
Product Price
and
Product Category
Further down the page, I've looped through these with a foreach and a few 'ifs' so it only displays those products where the name contains 'x' in one div and displays those products where the name contains 'y' in another div.
I'm struggling to count how many products are going to be in each div before I do the loop.
So essentially, what I'm asking is:
How do you count all elements in an array that satisfy a certain condition?
Added Code which shows the loop:
<div id="a">
<?php
$i = 1;
foreach ($products AS $product) {
if (strpos($product->name,'X') !== false) {
=$product->name
}
$i++;
} ?>
</div>
<div id="b">
$i = 1;
foreach ($products AS $product) {
if (strpos($product->name,'Y') !== false) {
=$product->name
}
$i++;
} ?>
</div>
I'd like to know how many of these are going to be in here before I actually do the loop.
Well, without seeing the code, so generally speaking, if you're going to split them anyway, you might as well do that up-front?
<?php
// getting all the results.
$products = $db->query('SELECT name FROM foo')->fetchAll();
$div1 = array_filter($products, function($product) {
// condition which makes a result belong to div1.
return substr('X', $product->name) !== false;
});
$div2 = array_filter($products, function($product) {
// condition which makes a result belong to div2.
return substr('Y', $product->name) !== false;
});
printf("%d elements in div1", count($div1));
printf("%d elements in div2", count($div2));
// then print the divs. No need for ifs here, because results are already filtered.
echo '<div id="a">' . PHP_EOL;
foreach( $div1 as $product ) {
echo $product->name;
}
echo '</div>';
echo '<div id="b">' . PHP_EOL;
foreach( $div2 as $product ) {
echo $product->name;
}
echo '</div>';
That being said: you should take notice of the comment which says "This is normally faster in SQL", because it is the more sane approach if you want to filter the values.
EDIT: Changed the name of the variables to adapt the variable names in the example code.
Use an array-filter: http://www.php.net/manual/en/function.array-filter.php
array array_filter ( array $input [, callable $callback = "" ] )
Iterates over each value in the input array passing them to the callback function. If the callback function returns true, the current value from input is returned into the result array. Array keys are preserved.
<?php
function odd($var)
{
// returns whether the input integer is odd
return($var & 1);
}
function even($var)
{
// returns whether the input integer is even
return(!($var & 1));
}
$array1 = array("a"=>1, "b"=>2, "c"=>3, "d"=>4, "e"=>5);
$array2 = array(6, 7, 8, 9, 10, 11, 12);
echo "Odd :\n";
print_r(array_filter($array1, "odd"));
echo "Even:\n";
print_r(array_filter($array2, "even"));
?>
But be aware, this is a loop though, and your the SQL query will be faster.

Categories