I need to check if an event has an offer and i have made this function
public function hasAcceptedOffer()
{
foreach ($this->offers as $offer) {
if( $offer->accepted == 1 ){
return true;
} else {
return false;
}
}
But i think this can be made better, more optimized. Because if there are a lot of offers i don't want to go through all of them. What i want is that if a function finds an offer that is accepted it should stop further iteration.
I think you did good here.
You can remove the else part by doing this
public function hasAcceptedOffer()
{
foreach ($this->offers as $offer) {
if( $offer->accepted == 1 ){
return true;
}
}
return false;
}
Assuming you only care if any offer was accepted, and you don't need to know which one, I like to do it like this:
public function hasAcceptedOffer()
{
foreach($this->offers as $offer) {
if($offer->accepted !== 1)
continue;
return true;
}
return false;
}
Each iteration of the loop will quickly skip to the next one if it doesn't match your desired criteria, it will return immediately when it finds the first positive result and skip processing the others (since you don't care anyway) and return false if no matches are found.
If you want to collect the offers that were accepted, you can amend it like so:
public function getAcceptedOffers()
{
$results = array();
foreach($this->offers as $offer) {
if($offer->accepted !== 1)
continue;
$results[] = $offer;
}
return $results;
}
Related
So I have a function that currently has a foreach and it works amazing, but I'm being forced to change it to a while loop:
PLEASE NOTE: The developers at my company don't want to use the foreach and they think that a while loop would be more efficient, but I'm not understanding how that would be executed, so I need some help.
So I have the following function ($post_blocks is an array of arrays):
public function parse_block_data(string $block_name, string $selector, $post_id)
{
if (!has_blocks($post_id)) {
return false;
}
$post_blocks = parse_blocks(get_the_content('', false, $post_id));
foreach ($post_blocks as $block) {
if ($block_name != $block['blockName']) {
continue;
}
if (!isset($block['attrs']['id'])) {
return false;
}
if (isset($block['attrs']['data'][$selector])) {
return $block['attrs']['data'][$selector];
} else {
break;
}
}
return false;
}
It uses the parameters to build up an array as shown below:
Output
So I started building a while loop inside the function, but I'm clueless on how to achieve it without using a foreach or if it's even possible, so I replaced the foreach with:
// I get the 9 counts of $post_blocks correctly.
$block = 0;
while ($block < count($post_blocks))
// If the $block_name doesn't match `blockName` value inside the multi-dimensional array, then continue iterating until the end and then return false.
// If ['attrs']['id'] is not set, return false.
// At last, if we have a blockName and a ID and the selector is set, return ['attrs']['data'][$selector]
}
All help will be appreciated! It makes no sense to me, but if someone can assist, I'd be forever grateful!
It's basically the same as your foreach loop, you just set the iteration variable by indexing the array, and increment the index manually.
$block_num = 0;
while ($block_num < count($post_blocks)) {
$block = $post_blocks[$block_num];
if ($block_name == $block['blockName']) {
if (!isset($block['attrs']['id'])) {
return false;
}
if (isset($block['attrs']['data'][$selector])) {
return $block['attrs']['data'][$selector];
} else {
break;
}
}
$block_num++;
}
I'm not sure why your colleagues think this is preferable.
If there's a company coding style they want you to follow, why don't you ask them what it should be?
I am looking to find a way to detect cycle in linked list using Array in PHP. Please note I am aware of two pointer approach but I am keen on understanding approach if it is feasible to achieve this with php array.
in Java code sample on leetcode is as below:
public boolean hasCycle(ListNode head) {
Set<ListNode> nodesSeen = new HashSet<>();
while (head != null) {
if (nodesSeen.contains(head)) {
return true;
} else {
nodesSeen.add(head);
}
head = head.next;
}
return false;
}
Based on the given info I would rewrite it like this utilizing also an array as hashmap for visited nodes.
function hasCycle(SplDoublyLinkedList $list): bool
{
$nodesSeen = [];
$list->rewind();
while ($current = $list->current()) {
if (isset($nodesSeen[$current]))
return true;
$nodesSeen[$current] = true;
$list->next();
}
return false;
}
Testing with having a cycle on a.
$list = new SplDoublyLinkedList();
$list->push('a');
$list->push('b');
$list->push('c');
$list->push('a');
var_dump(hasCycle($list));
true
Testing with having no cycle.
$list = new SplDoublyLinkedList();
$list->push('a');
$list->push('b');
$list->push('c');
$list->push('d');
var_dump(hasCycle($list));
false
one more approach I have come across (no that efficient though):
function hasCycle($head) {
$prev = [];
while($head){
if(in_array($head, $prev)) {
return true;
}
$prev[] = $head;
$head= $head->next;
}
return false;
}
This question already has answers here:
How to use return inside a recursive function in PHP
(4 answers)
Closed 9 months ago.
I have a problem with a recursive function in PHP which returns a JSON object. When the the condition is met to run the function a second time I always get an empty object as result {}. Everything is executed as it would be in the first run, but I always get an empty result.
Here is my code (very much simplified, yet functioning):
public function run()
{
$result = null;
// .......
// there is alot other stuff here, that all runs
// perfectly through also the second run
// ......
// Conditional Routing
if($this->wfProfile->autoprocess){
// select new wfProfile and go again.
$this->autoprocess(function($data){
if($data['error']==0){
$result = null;
$this->run(); // from here we start over !
}else{
return $data;
}
});
}else{
return ['error'=>0,'message'=>'all good']; // this is where it should go at the end of second loop
}
}
There is no place in the whole class, that would return an empty JSON object. Something must be here, that I'm doing wrong or what I'm overseeing.
Edit (I don't think this helps)
private function autoprocess($callback)
{
if(is_callable($callback)){
$possibleWFprofiles = WfProfile::where('statusNow', $this->wfRequest->status)->where('conditionalRouting', 1)->get();
if($possibleWFprofiles->count() == 0){
// configuration error....
$result = ["error"=>1, 'message'=>"Unable to find Conditional Routing enabled WfProfiles: ".$this->wfRequest->status];
}
foreach($possibleWFprofiles as $possibleWfProfile){
if(array_search($possibleWfProfile->crFieldname, $this->wfRequestFields)===false){
// fieldname wrongly configured
$result = ["error"=>1, 'message'=>"Unable to find field ".$possibleWfProfile->crFieldname];
}
// see if this is the right one
if($this->wfRequest[$possibleWfProfile->crFieldname] == $possibleWfProfile->crValue){
$this->wfProfile = $possibleWfProfile;
$result = ['error'=>0,'message'=>'Off to loop 2'];
}
}
call_user_func($callback, $result);
}
}
When you make a return $data, inside a anonymous function, it will not be a run's return.
You are not doing nothing with this return in your autoprocess function.
You need to return something in autoprocess and then return in your if:
if($this->wfProfile->autoprocess){
// select new wfProfile and go again.
return $this->autoprocess(function($data){
if($data['error']==0){
$result = null;
return $this->run(); // from here we start over !
}else{
return $data;
}
});
}else{
return ['error'=>0,'message'=>'all good']; // this is where it should go at the end of second loop
}
You need to return your value, for example take this:
function callback($func, $val) {
return call_user_func($func, $val);
}
function run($val) {
if ($val < 10) {
callback(function($val) { return run($val + 1); }, $val);
}
return $val;
}
print(run(0));
this will print empty, but if you do:
function callback($func, $val) {
return call_user_func($func, $val);
}
function run($val) {
if ($val < 10) {
return callback(function($val) { return run($val + 1); }, $val);
}
return $val;
}
print(run(0));
it will print 10
Your function:
public function run()
{
$result = null;
// lets say this is true...
if($this->wfProfile->autoprocess){
// now we are here, where does this return a value???
$this->autoprocess(function($data){
// if it goes here, it never returns a value.
if($data['error']==0){
$result = null;
$this->run(); // from here we start over !
}else{ // if it returns here it still just returns to
// $this->autoprocess, which might return to the
// original run function, but you don't seem to be
// returning its return either...
return $data;
}
});
}else{
return ['error'=>0,'message'=>'all good']; // this is where it should go at the end of second loop
}
}
At the end I chose the imho less elegant way to solve this, so I used goto instead of calling the function again. This is easy to read and to debug/extend in future. So here we go:
public function run()
{
startover:
$result = null;
// more stuff going on here
// Conditional Routing
if($this->wfProfile->autoprocess){
// select new wfProfile and go again.
$result = $this->autoprocess();
if($result['error']==0){
goto startover; // easiest way :-)
}else{
return $result;
}
}else{
return ['error'=>0,'message'=>'all good'];
}
}
and here the autoprocess function
private function autoprocess()
{
$possibleWFprofiles = WfProfile::where('statusNow', $this->wfRequest->status)->where('conditionalRouting', 1)->get();
if($possibleWFprofiles->count() == 0){
// configuration error....
return ["error"=>1, 'message'=>"Unable to find Conditional Routing enabled WfProfiles: ".$this->wfRequest->status];
}
foreach($possibleWFprofiles as $possibleWfProfile){
if(array_search($possibleWfProfile->crFieldname, $this->wfRequestFields)===false){
// fieldname wrongly configured
return ["error"=>1, 'message'=>"Unable to find field ".$possibleWfProfile->crFieldname];
}
// see if this is the right one
if($this->wfRequest[$possibleWfProfile->crFieldname] == $possibleWfProfile->crValue){
$this->wfProfile = $possibleWfProfile;
return ['error'=>0,'message'=>'Off to loop 2'];
}
}
}
I want to check all elements of an array and find out, whether at least one of them is prefixed by a given string:
public function validateStringByPrefix(string $string, $prefix)
{
$valid = false;
if (is_string($prefix)) {
if (strpos($string, $prefix) === 0) {
$valid = true;
}
} elseif (is_array($prefix)) {
foreach ($prefix as $partPrefix) {
if (strpos($string, $partPrefix) === 0) {
$valid = true;
break;
}
}
}
return $valid;
}
Is it possible / How to to achieve the same a more efficient way?
(It's a cheap method, but it's called a lot of times in my application, so even a minimal improvement might appreciably increase the application's performance.)
You can try next solution:
public function validateStringByPrefix(string $string, $prefix)
{
return (bool)array_filter((array)$prefix, function($prefix) use ($string) {
return strpos($string, $prefix)===0;
});
}
P.S. In case you have few large arrays (with prefixes), my solution is less efficient and you can combine our approaches like this:
public function validateStringByPrefix(string $string, $prefix)
{
if($string=='') {
return false;
}
foreach ((array)$prefix AS $subprefix) {
if (strpos($string, $subprefix)===0) {
return true;
}
}
return false;
}
There are many ways to rome....
//your array to test for
$array=[];
//set valid to false
$valid=false;
//setup prefixes array or not
$prefix='whatever';
//make array if you dont have one
!is_array($prefix) AND $prefix=array($prefix);
//prepare for use as REGEX
$prefix=implode('|',$prefix);
//do the work
array_walk($array,function($val,$key) use(&$valid,$prefix){
if (!$valid && preg_match("#^($prefix)#",$key)) {
$valid = true;
}
});
var_export($valid);
I used preg_match here, because $prefix can be an array, so the math would be: n+ strpos() calls vs. one preg_match() call
And after a single item matches, no more preg_match are called, just iteration to the end and out.
Is it possible to return an array, but also tell php it's supposed to mean false?
Example:
if ($res = a_function()) {
// all good
}
else {
echo getErrorByNumber($res['err_no']);
}
a_function:
function a_function() {
// do fancy stuff
if (xy) return true;
return array('err_no' => 1);
}
I guess its not possible, since php will always take an array for return true, right?
Lot's of ways. Probably the preferred one, compare to true with type checking ===:
if(($res = a_function()) === true) {
// all good
}
else {
echo getErrorByNumber($res['err_no']);
}
A non-empty array will always be true:
if($res = a_function() && !is_array($res)) {
// all good
}
else {
echo getErrorByNumber($res['err_no']);
}
Or flip it around:
if(is_array($res)) { //or isset($res['err_no'])
echo getErrorByNumber($res['err_no']);
}
else {
// all good
}
I would solve this problem with a byref parameter:
function foo(&$errors)
{
if (allWentWell())
{
$errors = null;
return true;
}
else
{
$errors = array('err_no' => 007);
return false;
}
}
// call the function
if (foo($errors))
{
}
else
{
echo getErrorByNumber($errors['err_no']);
}
This way you do not have to distinguish between different possible return types and you will not run into type juggling problems. It is also more readable, you know what's inside the $errors variable without documentation. I wrote a small article explaining why mixed-typed return values can be so dangerous.