Echo once per foreach - php

So I have the following code:
$colors=$ex->Get_Color("images/avatarimage3.png", $num_results, $reduce_brightness, $reduce_gradients, $delta);
foreach ( $colors as $hex => $count )
{
if ($hex == 'e6af23' && $count > 0.05)
{
echo "The image has the correct colour";
}
else
{
echo "The image doesn't have the correct colour";
}
}
Basically this code at the moment grabs the hex value and percentage of colours than image contains and adds them to an array. The code above looks to see if the hex is a certain value and the percent above 5% and if it is then it displays the success message. This part works exactly as it should do!
Now, what I also want is that if the colour isn't correct, so for all other hex values in the array other than $hex == 'e6af23' I want it to display a failure message but only display it once and not for every time the hex isn't that value.
Basically I need it so that the failure message is only displayed once and not 5 times (the number of hex colours in the image).

You can use a flag to indicate if the message has been outputted or not, and if so then don't output again:
$colors=$ex->Get_Color("images/avatarimage3.png", $num_results, $reduce_brightness, $reduce_gradients, $delta);
$error_displayed = false;
foreach ( $colors as $hex => $count ) {
if ($hex == 'e6af23' && $count > 0.05) {
echo "The image has the correct colour";
} else if (!$error_displayed) {
echo "The image doesn't have the correct colour";
$error_displayed = true;
}
}

Just keep a list of colors you already echoed.
$failed = array();
forech ($colors as $hex) {
if (!in_array($hex, $failed) && $error) {
echo 'Failed at hex ' . $hex;
$failed[] = $hex;
}
}

Using NewFurnitureRay's answer as a guideline I came up with this answer:
$colors=$ex->Get_Color("images/avatarimage.png", $num_results, $reduce_brightness, $reduce_gradients, $delta);
$success = true;
foreach ( $colors as $hex => $count ) {
if ($hex !== 'e6af23') {$success = false; }
if ($hex == 'e6af23' && $count > 0.05) {$success = true; break;}
}
if ($success) { echo "Success"; } else { echo "This is a failure"; }
Seems to work now as it should only displaying either a success or a failure regardless of the success's position in the array :)

Related

Any way to shorten this if statement? PHP

I'm trying to keep my code nice and elegant. Any way to make this if statement shorter?
if(strlen($cname) > 100) {
}
if(strlen($cowner) > 100) {
}
if(strlen($cemail) > 200) {
}
if(strlen($cpassword) > 100) {
}
I can't do this because I want to print out a specific message for each if statement:
if(strlen($cname) > 100 || strlen($cowner) > 100 || strlen($cemail) > 200 || strlen($cpassword) > 100) {
// I want to print out a message like email is too long not just one of these strings is too long
}
Frankly, I think you've got the most elegant solution for what you are trying to do.
You can use a loop to reduce the number of lines. Here is an optimized solution even when you have more 10 fields to check:
Declare an array of fields and loop through it
$fields = array("cname" => 100, "cowner" => 100, "cemail" => 200, "cpassword" => 100); // key as field name and value as maximum limit - new values can be added here.
foreach($fields as $field => $length) {
if(strlen(${$field}) > $length) {
die("$field field can only contain $length characters");
}
}
Edit: You can also keep all errors in an array and then print all the errors on your page.
$errors = array();
foreach($fields as $field => $length) {
if(strlen(${$field}) > $length) {
$errors[] = "$field field can only contain $length characters";
}
}
print_r($errors);
You already using an optimized code. But you can optimize it little bit more for showing error message. Like below:
$invalidFieldName = '';
$invalidFieldLength = 100;
if (strlen($cname) > 100) {
$invalidFieldName = 'CNAME';
} elseif (strlen($cowner) > 100) {
$invalidFieldName = 'COWNER';
} elseif (strlen($cemail) > 200) {
$invalidFieldName = 'CEMAIL';
$invalidFieldLength = 200;
} elseif (strlen($cpassword) > 100) {
$invalidFieldName = 'CPASSWORD';
}
if ($invalidFieldName != '') {
echo $invalidFieldName." should be greater than ".$invalidFieldLength;
}
I am not really sure if it will help you but I hope it will help you.

if print_r is empty conditional in PHP

I'm trying to get a n else statement working with a print_r such that if there's no value it outputs "no values".
In the code I'm getting values from json converted to an array.
The logic I'm trying to achieve is
IF fieldTag contains "i" THEN output the content associated with it
ELSE says its empty.
Right now blank is outputted as opposed to "no values".
Thanks
for($b=0; $b<count($res['entries'][$i]['bib']['varFields']); $b++) //loop thru the varFields
{
if($res['entries'][$i]['bib']['varFields'][$b]['fieldTag'] == "i")
{
$subfieldText2 = $res['entries'][$i]['bib']['varFields'][$b]['subfields'][0]['content']."<br>";
if(count($subfieldText2) > 0) {
print_r($subfieldText2);
} else {
echo "no values";
}
}
}
count() is for arrays, not strings, the way to get the length of a string is with strlen(). And if you want to check for an empty string, just compare it with $var == "", you don't need to get the length.
But you're concatenating "<br>" to the value, so the length will never be zero. You could check the length before concatenating.
$subfieldText2 = $res['entries'][$i]['bib']['varFields'][$b]['subfields'][0]['content'];
if($subfieldText2 != "") {
$subfieldText2 .= "<br>";
print_r($subfieldText2);
} else {
echo "no values";
}
And to avoid having to repeat that long expression to access the field, you could use foreach
for($res['entries'][$i]['bib']['varFields'] as $field) {
if ($field['fieldTag'] == "i") {
$subfieldText2 = $field['subfields'][0]['content'];
...
}
}
this worked for me thanks everyone
$subfieldText2="not detected";
echo "ISBN: ";
for($b=0; $b<count($res['entries'][$i]['bib']['varFields']); $b++) //loop thru the varFields
{
if($res['entries'][$i]['bib']['varFields'][$b]['fieldTag'] == "i")
{
$subfieldText2 = $res['entries'][$i]['bib']['varFields'][$b]['subfields'][0]['content'];
echo $subfieldText2.", ";
}
}
echo $subfieldText2;

why can't array_search find the value if the code of the key is "gb2312"?

my questions:
$state=array("你"=>1);
if(array_key_exists("你",$state))
{
$result = array_search("你",$state);echo $result;
}else
{
echo "No Exists";
}
i expect the result of "1", however the output is "No Exists", i don't know why the program can't get the value of the key "你".
array_search will search the given array by value. Try the following:
$state = array("你"=>1);
if(array_key_exists("你", $state)) {
echo $state["你"];
} else {
echo "No Exists";
}
// => 1
» demo
Hope below function will help.
<?php
$array = array('arr1'=>array('find_me'=>'yes you did.'));
function get_value_by_key($array,$key)
{
foreach($array as $k=>$each)
{
if($k==$key)
{
return $each;
}
if(is_array($each))
{
if($return = get_value_by_key($each,$key))
{
return $return;
}
}
}
}
echo get_value_by_key($array,'find_me');
?>
the encoding type of the show paper and the store paper is GB2312.
$state=array("你"=>1);
if(array_key_exists("你",$state))
{
$result1 = $state["你"];
echo $result1; // can get the value 111
}else
{
echo "No Exists";
}
the code above can be executed rightly. i can't show my problems accurately. Now i paste out my code , there is some questions.
<?php
$file = file("GB2312-HanZiBianMa.txt"); // file encoding type ANSI
foreach ($file as $line_num => $line)
{
list($no,$hex,$dec) = preg_split('[\t]',htmlspecialchars($line));;
$result[$hex] = $dec;
}
$result_2 = array_flip($result);
if(array_key_exists("你",$result_2)) // **can't find the value** 222
{
$state= $result_2["你"];
echo $state."<br/>";
}else
{
echo "No Exists<br/>";
}
foreach($result_2 as $k=>$each) //can get the value using the preg_match
{
if(preg_match('/你/', $k))
echo $k."\t".$each."<br/>";
}
?>
the format of GB2312-HanZiBianMa.txt is as follows:
1947 c4e3 你
1948 c4e4 匿
1949 c4e5 腻
1950 c4e6 逆
if your want to test the code , you can save the php code and save the GB2312.. file.
the question is:
why can't the following function get the right value ? the data comes from file and one stores together.
if(array_key_exists("你",$result_2)) // **can't find the value** 222
{
$state= $result_2["你"];
echo $state."<br/>";
}else
{
echo "No Exists<br/>";
}

How to echo some text inside a for-loop only once?

I have this piece of code
<?php for ($i=0;$i<sizeof($list["tags"]); $i++) {
if ($list["tags"][$i]["title"]=='list') {
echo 'Not correct type';
}
if ($list["tags"][$i]["title"]!='list') {
?>
Text
<?php }
}
?>
My problem is that when $list["tags"][$i]["title"]=='list', I get the message 'Not correct type' many times as the loop continues. How can I echo that message only once?
You can insert break; after the echo statement to exit the loop when the condition is met. Use break n; to exit out of n layers of loops/conditionals.
You'll just have to keep track of whether you've already shown it or not:
$shown = false;
for ( $i = 0; $i < sizeof( $list['tags'] ); $i++ ) {
if ( $list['tags'][$i]['title'] == "list" && !$shown ) {
echo "Not correct type";
$shown = true;
}
if ( $list['tags'][$i]['title'] != "list" ) {
echo 'Text';
}
}
But this raises the question: why would you only want the message to show once? Wouldn't you want it to display "Not correct type" for all values of $i for which the title is not "list"?

Help pulling out data from a PHP array based on 5 rules

I'm working with arrays of image filepaths. A typical array might have 5 image filepaths stored in it.
For each array, I want to pull out just the "best" photo to display as a thumbnail for the collection.
I find looping and arrays very confusing and after 4 hours of trying to figure out how to structure this, I'm at a loss.
Here are the rules I'm working with:
The very best photos have "-large" in their filepaths. Not all arrays will have images like this in them, but if they do, that's always the photo I want to pluck out.
The next best photos are 260px wide. I can look this up with getimagesize. If I find one of these, I want to stop looking and use it.
The next best photos are 265 wide. If I find one I want to use it and stop looking.
The next best photos are 600px wide. Same deal.
Then 220px wide.
Do I need 5 separate for loops? 5 nested for-loops
Here's what I'm trying:
if $image_array{
loop through $image_array looking for "-large"
if you find it, print it and break;
if you didn't find it, loop through $image_array looking for 260px wide.
if you find it, print it and break;
}
and so on....
But this doesn't appear to be working.
I want to "search" my array for the best single image based on these criteria. If it can't find the first type, then it looks for the second on so on. How's that done?
// predefined list of image qualities (higher number = best quality)
// you can add more levels as you see fit
$quality_levels = array(
260 => 4,
265 => 3,
600 => 2,
220 => 1
);
if ($image_arry) {
$best_image = null;
// first search for "-large" in filename
// because looping through array of strings is faster then getimagesize
foreach ($image_arry as $filename) {
if (strpos('-large', $filename) !== false) {
$best_image = $filename;
break;
}
}
// only do this loop if -large image doesn't exist
if ($best_image == null) {
$best_quality_so_far = 0;
foreach ($image_arry as $filename) {
$size = getimagesize($filename);
$width = $size[0];
// translate width into quality level
$quality = $quality_levels[$width];
if ($quality > $best_quality_so_far) {
$best_quality_so_far = $quality;
$best_image = $filename;
}
}
}
// we should have best image now
if ($best == null) {
echo "no image found";
} else {
echo "best image is $best";
}
}
Another approach (trivial, less generic, slower). Just check rules one by one:
function getBestFile($files) {
foreach ($files as $arrayKey => $file) {
if (strstr($file, '-large') !== FALSE) {
return $file;
}
}
foreach ($files as $arrayKey => $file) {
if (is260wide($file)) {
return $file;
}
}
// ...
}
You need 3 loops and a default selection.
loop through $image_array looking for "-large"
if you find it, return it;
if you didn't find it, loop through $image_array
get image width
if prefered width (260px), return it.
if $sizes[$width] not set, add filename
loop a list of prefered sizes in order and see if it is set in $sizes
if you find it, return it;
return the first image or default image;
<?php
// decide if 1 or 2 is better
function selectBestImage($image1, $image2) {
// fix for strange array_filter behaviour
if ($image1 === 0)
return $image2;
list($path1, $info1) = $image1;
list($path2, $info2) = $image2;
$width1 = $info1[0];
$width2 = $info2[0];
// ugly if-block :(
if ($width1 == 260) {
return $image1;
} elseif ($width2 == 260) {
return $image2;
} elseif ($width1 == 265) {
return $image1;
} elseif ($width2 == 265) {
return $image2;
} elseif ($width1 == 600) {
return $image1;
} elseif ($width2 == 600) {
return $image2;
} elseif ($width1 == 220) {
return $image1;
} elseif ($width2 == 220) {
return $image2;
} else {
// nothing applied, so both are suboptimal
// just return one of them
return $image1;
}
}
function getBestImage($images) {
// step 1: is the absolutley best solution present?
foreach ($images as $key => $image) {
if (strpos($image, '-large') !== false) {
// yes! take it and ignore the rest.
return $image;
}
}
// step 2: no best solution
// prepare image widths so we don't have to get them more than once
foreach ($images as $key => $image) {
$images[$key] = array($image, getImageInfo($image));
}
// step 3: filter based on width
$bestImage = array_reduce($images, 'selectBestImage');
// the [0] index is because we have an array of 2-index arrays - ($path, $info)
return $bestImage[0];
}
$images = array('image1.png', 'image-large.png', 'image-foo.png', ...);
$bestImage = getBestImage($images);
?>
this should work (i didn't test it), but it is suboptimal.
how does it work? first, we look for the absolutely best result, in this case, -large, because looking for a substrings is inexpensive (in comparsion).
if we don't find a -large image we have to analyze the image widths (more expensive! - so we pre-calculate them).
array_reduce calls a filtering function that takes 2 array values and replaces those two by the one return by the function (the better one). this is repeated until there is only one value left in the array.
this solution is still suboptimal, because comparisons (even if they're cheap) are done more than once. my big-O() notation skills are a bit (ha!) rusty, but i think it's O(n*logn). soulmerges solution is the better one - O(n) :)
you could still improve soulmerges solution, because the second loop is not necessary:
first, pack it into a function so you have return as a break-replacement. if the first strstr matches, return the value and ignore the rest. afterwards, you don't have to store the score for every array key. just compare to the highestKey variable and if the new value is higher, store it.
<?php
function getBestImage($images) {
$highestScore = 0;
$highestPath = '';
foreach ($images as $image) {
if (strpos($image, '-large') !== false) {
return $image;
} else {
list($width) = getImageInfo($image);
if ($width == 260 && $highestScore < 5) {
$highestScore = 5;
$highestPath = $image;
} elseif ($width == 265 && $highestScore < 4) {
$highestScore = 4;
$highestPath = $image;
} elseif ($width == 600 && $highestScore < 3) {
$highestScore = 3;
$highestPath = $image;
} elseif ($width == 220 && $highestScore < 2) {
$highestScore = 2;
$highestPath = $image;
} elseif ($highestScore < 1) {
// the loser case
$highestScore = 1;
$highestPath = $image;
}
}
}
return $highestPath;
}
$bestImage = getBestImage($images);
?>
didn't test, should work in O(n). can't imagine a faster, more efficient way atm.
I would assign points to the files depending on how many rules apply. If you want certain rules to supercede others, you can give more points for that rule.
define('RULE_POINTS_LARGE', 10);
define('RULE_POINTS_260_WIDE', 5);
// ...
$points = array();
foreach ($files as $arrayKey => $file) {
$points[$arrayKey] = 0;
if (strstr($filename, '-large') !== FALSE) {
$points[$arrayKey] += RULE_POINTS_LARGE;
}
// if ...
}
// find the highest value in the array:
$highestKey = 0;
$highestPoints = 0;
foreach ($points as $arrayKey => $points) {
if ($files[$arrayKey] > $highestPoints) {
$highestPoints = $files[$arrayKey];
$highestKey = $arrayKey;
}
}
// The best picture is $files[$highestKey]
One more side note: Givign your rules multiples of a value will ensure that a rule can be 'stronger' than all others. Example: 5 rules -> rule values (1, 2, 4, 8, 16).
1 < 2
1 + 2 < 4
1 + 2 + 4 < 8
etc.

Categories