I made a horrible loop.... help fix my logic please - php

I know I'm doing this a bad way... but I'm having trouble seeing any alternatives. I have an array of products that I need to select 4 of randomly. $rawUpsellList is an array of all of the possible upsells based off of the items in their cart. Each value is a product object. I know this is horribly ugly code but I don't see an alternative now.... someone please put me out of my misery so this code doesn't make it to production.....
$rawUpsellList = array();
foreach ($tru->global->cart->getItemList() as $item) {
$product = $item->getProduct();
$rawUpsellList = array_merge($rawUpsellList, $product->getUpsellList());
}
$upsellCount = count($rawUpsellList);
$showItems = 4;
if ($upsellCount < $showItems) {
$showItems = $upsellCount;
}
$maxLoop = 20;
$upsellList = array();
for ($x = 0; $x <= $showItems; $x++) {
$key = rand(0, $upsellCount);
if (!array_key_exists($key, $upsellList) && is_object($rawUpsellList[$key])) {
$upsellList[$key] = $rawUpsellList[$key];
$x++;
}
if ($x == $maxLoop) {
break;
}
}
Posting this code was highly embarassing...

Actually, pulling randomly from an array is a tough nut to crack - even Microsoft had trouble recently. That's a decent code sample for someone who I assume isn't an expert in algorithms, but also may be statistically skewed. As I said, it's difficult to do this right.
Thankfully, PHP already has the function array_rand, which seems to do what you want: return N items randomly chosen from an array. Is that what you're looking for?
$upsellList = array_rand($rawUpsellList, 4);

I am not really into PHP, but as an algorithm I will consider this pseudocode or whatever:
List<WhateverTypeYouWant> array;
List<WhateverTypeYouWant> selectedElements;
for (int i = 1; i <= 4; i++)
{
int randomIndex = random(array.size());
selectedElements.add(array[randomIndex]);
array.remove(randomIndex);
}

array_rand will let you pick one or more elements randomly from an array.
To use it (and save yourself a lot of headache), simply do something like
$upsellList = array_rand($rawUpsellList, 4);

Related

PHP - Using the += operator on an undefined array index

I'm using data pulled from an SQL query to build two charts later in my code. And example query would be something like:
SELECT purchase_location, purchase_item, SUM(purchase_amount) as totalPurchase
FROM purchases
GROUP BY purchase_item_id, purchase_location
Not an exact example, but the idea is there. I then iterate through my results to build the two data sets.
$locationData = [];
$itemData = [];
foreach($queryResults as $result) {
$locationData[$result['purchase_location']] += $result['totalPurchase'];
$itemData[$result['purchase_item']] += $result['totalPurchase'];
}
Since I want the data from two different points of view, I have to use += to get the correct totals. My question is this: doing the += operator on an unset index of an array is incredibly slow. I've found that if I do the following:
if (isset($locationData['purchase_location'])) {
$locationData['purchase_location'] += $result['totalPurchase'];
} else {
$locationData['purchase_location'] = $result['totalPurchase'];
}
Using an = for the first time the index is seen. This speeds up the code significantly (As an example, my code went from 8-10 second run time down to less than half a second). My question is, is that the correct/cleanest way to handle this?
And before anyone mentions, I know I could write the query to handle all of this in this simple case, this was just a really easy example to show the issue, that of using += on an, as of yet, undefined array index.
I would suggest initializing the array with that index already, avoiding the need for isset checks and making the code cleaner:
$locationData = ['purchase_location' => 0];
$itemData = ['purchase_item' => 0];
foreach($queryResults as $result) {
$locationData['purchase_location'] += $result['totalPurchase'];
$itemData['purchase_item'] = $result['totalPurchase'];
}
For my projects I usually try to limit the usage of isset to the validation of received data from outside sources (ex: GET, POST) that I can't fully control.
Since you've updated you're answer, now it makes sense to use isset in this case to avoid another loop to construct the array.
$locationData = [];
$itemData = [];
foreach($queryResults as $result) {
if (!isset($locationData[$result['purchase_location']])) {
$locationData[$result['purchase_location']] = 0;
}
if (!isset($itemData[$result['purchase_item']])) {
$itemData[$result['purchase_item']] = 0;
}
$locationData[$result['purchase_location']] += $result['totalPurchase'];
$itemData[$result['purchase_item']] += $result['totalPurchase'];
}
If you're using PHP 7+ you can use the null coalesce ?? to simplify your code like this:
$locationData = [];
$itemData = [];
foreach($queryResults as $result) {
$locationData[$result['purchase_location']] = $result['totalPurchase'] + ($locationData[$result['purchase_location']] ?? 0);
$itemData[$result['purchase_item']] = $result['totalPurchase'] + ($itemData[$result['purchase_item']] ?? 0);
}
You could try the following:
$locationData = [];
$itemData = [];
foreach($queryResults as $result) {
$locationData[$result['purchase_location']] = ($locationData[$result['purchase_location']]??0) + $result['totalPurchase'];
$itemData[$result['purchase_item']] = ($itemData[$result['purchase_item']]??0) + $result['totalPurchase'];
}
But I think it's cleaner and more obvious just to initialise everything to zero separately first:
foreach($queryResults as $result) {
$locationData[$result['purchase_location']] = 0;
$itemData[$result['purchase_item']] = 0;
}
and then do the work of addition in another loop.
for your question, yes you need to create this index before adding += to this index.
instead of check it every iteration, so just configure it before the foreach loop, and then this index will exits and you will be able to sum += and thats all
$locationData = [
'purchase_location' => 0
];
$itemData = [];
foreach($queryResults as $result) {
$locationData['purchase_location'] += $result['totalPurchase'];
$itemData['purchase_item'] = $result['totalPurchase'];
}
My question is, is that the correct/cleanest way to handle this?
Without example data and expected results it's hard to know that results you are after.
A educated guess would be using MySQL WITH ROLLUP GROUP BY Modifier to get a added total record.
SELECT purchase_location, purchase_item, SUM(purchase_amount) as totalPurchase
FROM purchases
GROUP BY purchase_item_id, purchase_location WITH ROLLUP

Retrieve POST items with different names

I'm passing some values with POST to another file.
One (or more) of those values are:
Equip1, Equip2, Equip3, ..., EquipN
I'm able to know how many EquipN I have, but not know how to get their values.
I thought this works, but it's not:
for ($Equip_aux=1; $Equip_aux<=$Number_of_Equip; $Equip_aux++) {
$aux = "'Equipamento".$Equip."'";
$VALUE = $_POST[$aux];
}
Any help, please?
I'm able to know how many EquipN I have, but not know how to get their values.
Here's the corrected version of your for loop:
for ($i = 1; $i <= $Number_of_Equip; $i++) {
$aux = "Equip$i";
$VALUE = $_POST[$aux];
}
Notice that you can also loop trough the post values with foreach:
foreach ($_POST as $p) {
...
}

How Do I store my POST While Loop

Let me know if you want more details but:
I have an different number of inserts I need to make based on a POST form data that I created in a loop.
If I were to write it all out it would look like this:
$Scout1=$_POST['ScoutID1'];
$Scout2=$_POST['ScoutID2'];
and it keeps going until it reaches "x" I do have that number stored as
$ScoutCount
(so if the above code would post all the variables I brought over {$ScoutCount=2}
I can't find a way to do:
while (X>0){
$ScoutX=$_POST['ScoutIDX'];
X--;
}
how can I do this?
You might be looking for variable variables
But rather, I would recommend storing the data in an array, as opposed to individual variables. Then in a for loop, it could look like:
$scouts = array();
for ($i = 0; $i < 10; $i++)
{
$scouts[$i] = $_POST['ScoutID' . $i];
}
or something.
instead of having form fields called ScoutID1, ScoutID2 wtc name them
name="ScoutID[]"
then you will have a nice array with work with
//put scoutIDs into Array
$scouts = array();
for ($i = 1; $i <= $ScoutCount; $i++)
{
$scouts[$i] = $_POST['ScoutID' . $i];
}
Thanks - that may have seemed easy but I wasted a day trying to figure it out. thanks from the newbie to Php....

How would I loop through this?

I have a large array.
In this array I have got (among many other things) a list of products:
$data['product_name_0'] = '';
$data['product_desc_0'] = '';
$data['product_name_1'] = '';
$data['product_desc_1'] = '';
This array is provided by a third party (so I have no control over this).
It is not known how many products there will be in the array.
What would be a clean way to loop though all the products?
I don't want to use a foreach loop since it will also go through all the other items in the (large) array.
I cannot use a for loop cause I don't know (yet) how many products the array contains.
I can do a while loop:
$i = 0;
while(true) { // doing this feels wrong, although it WILL end at some time (if there are no other products)
if (!array_key_exists('product_name_'.$i, $data)) {
break;
}
// do stuff with the current product
$i++;
}
Is there a cleaner way of doing the above?
Doing a while(true) looks stupid to me or is there nothing wrong with this approach.
Or perhaps there is another approach?
Your method works, as long as the numeric portions are guaranteed to be sequential. If there's gaps, it'll miss anything that comes after the first gap.
You could use something like:
$names = preg_grep('/^product_name_\d+$/', array_keys($data));
which'll return all of the 'name' keys from your array. You'd extract the digit portion from the key name, and then can use that to refer to the 'desc' section as well.
foreach($names as $name_field) {
$id = substr($names, 12);
$name_val = $data["product_name_{$id}"];
$desc_val = $data["product_desc_{$id}"];
}
How about this
$i = 0;
while(array_key_exists('product_name_'.$i, $data)) {
// loop body
$i++;
}
I think you're close. Just put the test in the while condition.
$i = 0;
while(array_key_exists('product_name_'.$i, $data)) {
// do stuff with the current product
$i++;
}
You might also consider:
$i = 0;
while(isset($data['product_name_'.$i])) {
// do stuff with the current product
$i++;
}
isset is slightly faster than array_key_exists but does behave a little different, so may or may not work for you:
What's quicker and better to determine if an array key exists in PHP?
Difference between isset and array_key_exists

Problem with "auto-naming" an array

The title isn't very descriptive and I apologize, but I couldn't think of a better way to explain it. I have up to 10 serialized arrays in a database. I pull them down and unserialize them into a new array as such:
$specimen0 = unserialize($row['specimen0']);
$specimen1 = unserialize($row['specimen1']);
This is then formatted into an ordered list showing the specimens. Since there is a ton of data for each specimen I don't want to code it over and over again 10 times. My while loop looks as such:
while($i <= $num) {
if(isset($specimen{$i})) {
echo 'Yep';
}
$i++
}
That is the generalized version. For some reason the i variable isn't appending itself to the specimen variable to create the one size fits all variable I want. This is probably something simple that I'm over looking or php won't handle it the way I need. Any help would be greatly appreciated.
while($i <= $num) {
$target='specimen'.$i;
if(isset($$target)) {
echo 'Yep';
}
$i++
}
look at variable variables
Fatherstorm described how to correct you code very well. what makes me wonder is this: why don't you use an array like this:
$specimen = array();
$specimen[0] = unserialize($row['specimen0']);
$specimen[1] = unserialize($row['specimen1']);
// maybe you could also use an foreach($specimen as $key=>$array) here,
// don't know what you're trying to do...
while($i <= $num) {
if(isset($specimen[$i])) {
echo 'Yep';
}
$i++
}
otherwise you would have to use variable variables like the others mentioned - and this will end up in unreadable (and unmaintainable) code. if you want to use something like an array, take an array for the job.
while($i <= $num) {
$var='specimen'.$i;
if(isset(${$var})) {
echo 'Yep';
}
$i++
}
what you tried to do:
$str='abcdef';
echo $str{4}; //echo e;
$i=3;
echo $str{$i};//echo d

Categories