I have a function called combined which is going to loop through an array of orders. It is specifically searching for someone who placed more than 1 order and matches based on the customer's name and address line 1. If the customer places 2 orders this will catch them and combine them however if they have 3 or more if only catches 2. When I recursively call the function I get an invalid offset error which I do not understand as I thought the array index would refresh on every function call?
function combined(Array $all) {
//find any matching single orders and combine
$count = count($all);
$combinedorder = array();
for($i=1; $i < $count; $i++) {
for($j=1; $j < $count; $j++) {
//if order # is not the same
if(strcasecmp($all[$i][0], $all[$j][0]) !== 0){
//if name matches
if(strcasecmp($all[$i][2], $all[$j][2]) == 0) {
//if address line 1 matches
if(strcasecmp($all[$i][3], $all[$j][3]) == 0) {
$combinedorder[] = array('ordernos' => array($all[$i][0], $all[$j][0]), $all[$i][1], $all[$i][2], $all[$i][3], $all[$i][4], $all[$i][5], $all[$i][6], $all[$i][7], $all[$i][8], $all[$i][9], $all[$i][10], 'orders' => array($all[$i][11], $all[$j][11]));
unset($all[$i]);
unset($all[$j]);
$all = array_merge($all, $combinedorder);
$all = array_values($all);
reset($all);
//this recursive call does not work. undefined offset error
combined($all);
}
}
}
}
}
return $all;
}
You need to re-index the array. You are deleting some of the indexes with unset($all[$i]) and unset($all[$j]). So when the function calls itself and your loop hits the index that you deleted you get the invalid offset error.
To fix it just add this code after you unset some of the indexes to reset the keys of the array.
$all = array_values($all);
Related
I am trying to create a number of arrays to add to a larger array which I will then index two dimensionally (for example my_array[i][j]).
I believe I am having some type of pointing issue... I am iterating through a loop.... at the top of each iteration I instantiate a new array with the same name. When I try and view the output each item in the array appears blank.
Is there a better way for me to instantiate the "temp" arrays to fill the larger (outer) array? Really appreciate any and all help, this community has helped me through so many questions :D
$main_array = array();
for($i = 0; $i < $member_count; $i++)
{
$temp_array = array();
//preform SQL query here
$sql_get_member_transactions = 'some SQL query to go to my DB';
foreach($sql_get_member_transactions as $row)
{
//cannot get array to update here
array_push($temp_array, $row['amount']);
}
array_push($main_array, $temp_array);
}
#***FULL CODE BELOW***
$club_transactions = array();
for($i = 0; $i < $member_count; $i++)
{
#create an array for each member in the club,
#add each memeber's array to a larger array once filled with deposit amounts
#here check if member had a deposit (later we will check ALL transaction types...)
#if no deposit on that date add a zero to their array
$temp_member_transactions = array();
$temp_member = my_members[$i];
$sql_member_transactions = "SELECT * FROM Transactions WHERE Date >= '$first_t_date' AND Date <= '$last_t_date' AND RelatedClubID = 'THH'";
$sql_get_member_transactions = mysqli_query($conn, $sql_member_transactions);
//here we will get all transactions that lie within the
//event-transaction-date-window... in otherwords, the date window
//in the year where members transactions occured
foreach($sql_get_member_transactions as $row)
{
//we only want to include the transaction amount
//in the member-specific array if it belongs to that member
//otherwise see "else"
if($row['T_Owner'] == $temp_member)
{
$z = $row['T_Amount'];
}
else
{
//set to 0 so that we still account for the transaction date
$z = 0;
}
array_push($temp_member_transactions, $z);
}
array_push($club_transactions, $temp_member_transactions );
So basically i'm trying to create a complex timetable and i have these two methods that each perform a different check function for me:
Checks if i have a unique array
function tutorAllot($array,$check,$period){
//check for clashes and return non colliding allotment
shuffle($array);
$rKey = array_rand($array);
if(array_key_exists($array[$rKey]['teacher_id'], $check[$period])) {
return $this->tutorAllot($array,$check,$period);
}
return $tutor = array($array[$rKey]['teacher_id'] => $array[$rKey]['subject_code']);
}
checks that each subject does not appear more than twice in a day
function checkDayLimit($data,$check){
//check double day limit
$max = 2;
$value = array_values($check);
$tempCount = array_count_values($data);
return (array_key_exists($value[0], $tempCount) && $tempCount[$value[0]] <= $max) ? true : false;
}
I'm calling the functions from a loop and populating timetable array only if all conditions area satisfied:
$outerClass = array();
foreach ($value as $ky => $val) {
$innerClass = array(); $dayCount = array();
foreach ($periods[0] as $period => $periodData) {
$innerClass[$period] = array();
if(!($periodData == 'break')){
$return = $this->Schedule->tutorAllot($val,$clashCheck,$period);
if($return){
//check that the returned allocation hasnt reached day limit
if($this->Schedule->checkDayLimit($dayCount,$return)){
$innerClass[$period] += $return;
$clashCheck[$period] += $return;
}else{
}
}
}else{
$innerClass[$period] = '';
}
}
//debug($innerClass);
$outerClass[$ky] = $innerClass;
}
My requirements
If the checkDayLimit returns false , i want to go back and call tutorAllot function again to pick a new value.
I need to do this without breaking the loop.
I was thinking maybe i could use goto statement but only when am out of options.
Is there a way i can achieve this without using goto statement.
PHP v5.5.3 Ubuntu
Your architecture seems overly complex. Instead of
pick at random >> check limit >> if at limit, go to re-pick...
Why not incorporate both checks into a single function? It would
Filter out data that is not eligible to be picked, and return an array of legitimate choices
Pick at random from the safe choices and return the pick
addendum 1
I don't think there is any need for recursion. I would use array_filter to pass the data through a function that returns true for eligible members and false for the rest. I would then take the result of array_map and make a random selection from it
I've got a small problem. I'm working on a little package/product-list.
If you're watching a Package, my website should show you which products are in there.
If a product is more than one time in it, the array should be deleted and the value of the leftover array should be + 1 (each deleted array).
So here's my code:
// $products_in_package has all products in it
// First of all, the products come from a db and don't have a count
// So i first give them a count of 1
foreach ($products_in_package as $product => $value) {
$products_in_package[$product]['count'] = intval(1);
}
foreach ($products_in_package as $product) {
$id_to_find = intval($product['ID']);
$product_count = intval($product['count']);
$found_id = 0;
// Now I try to find any ident products
// If found and over 1 time (beacouse he finds the first too of course)
// Then delete this array and count up the products count
for ($i=0; $i <= count($products_in_package); $i++) {
if(intval($products_in_package[$i]['ID']) === $id_to_find){
$found_id++;
if($found_id > 1){
$product_count = $product_count + 1;
$product['count'] = $product_count;
unset($products_in_package[$i]);
array_merge($products_in_package);
while($i > $products_in_package){
$i = 0;
}
}
}
}
}
What I'm getting is the correct multidimensional array but the count is still 1.
What's wrong with the code?
Everytime I try to log the code i'm getting the right integer. (No, I already tried to delete the chache)
But if I log the array out of the loops, I get always the count of 1.
$product is a copy of the array element, so when you do $product['count'] = $product_count you're assigning to a copy, not the original array.
You can fix this by using a reference in the foreach:
foreach ($products_in_package as &$product) {
I am creating a function that calculate the quantity of sold tickets, and here is my code:
public function get_quantity($tickets_info){
$i = 0; //$i is the starting point of the loop
$k = 0;
$Qty = 1; // this is used to save the quantity of tickets, by default there is always one ticket
$index = array();
$quantity = array();
for($j = 1; $j < count($tickets_info); $j++) {
// if the ticket_id are the same, then increase the quantity by one
if($tickets_info[$i]['ticket_id'] == $tickets_info[$j]['ticket_id'])
{
$Qty++;
}
// if the ticket_id are not the same, then push the quantity into an array and remember the index
else
{
$idx = $j;//remember the index of the next first different ticket_id
$i = $j;//find the next starting point
$index[$k] = $idx;//push back the index of the next different ticket_id
$quantity[$k] = $Qty;//save quantity into the array
$k++;//increase the index poniter
$Qty = 1;//reset quantity back to one
}
}
// push the last quantity into the array
$quantity[$k+1] = $Qty;
//assign the ticket information into a new array
for($m = 0; $m < count($quantity); $m++){
$ticket[$m] = $tickets_info[$m];
}
//create the finally array, combine ticket information with quantity
$n = 0;
foreach($ticket as $row)
{
$row['Qty'] = $quantity[$n++];
}
return $ticket;
}
$ticket_info is a 2-D array which is generated from a SQL, and it has a structure like this:
$ticket_info
(
[0]=>array
(
[ticket_id] => 0001
[purchase_time] => 2014/01/02
....
)
[1]=>array
(
[ticket_id] => 0001
[purchase_time] => 2014/01/02
....
)
[2]=>array
(
[ticket_id] => 0001
[purchase_time] => 2014/01/02
....
)
....
)
Basically, if the tickets have the same ticket_id that means they have been bought at the same time (but in the database, I recorded them separately for a specific purpose), so I need to add them up and get the quantity.
I'm not familiar with PHP arrays, so I write my algorithm in C++ and tested it. It works fine. However, when I tried to write the real code in PHP, I got 2 errors:
For line, $ticket[$m] = $tickets_info[$m]; Message: Undefined offset: 0
For line, $row['Qty'] = $quantity[$n++]; Message: Undefined offset: 0
I don't know why there is no index 0, maybe I didn't initialize the array correctly or I didn't pass the data in $ticket_info in the right format? Can someone help me look at this code?
Do a check before you try access that index:
if (!empty($ticket) && !empty($tickets_info)) {
$ticket[$m] = $tickets_info[$m];
}
I am currently using php to help me find the valide and non-duplicated entry,
which i need
a list of valid and non-duplicated
entry a list of invalid input (unique)
a list of duplicate input
My approach is first create 5 array 2 for orginal ,1 for no mistake (empty),
1 for valid (empty) , 1 for duplicate (empty)
First using one of orginal array, for each one element : check valid
and check duplicate, if invalid , put into invalid array , and check duplicate by using inarray
after all, i get one array of invalid and duplicate , then using the orginal array, check which element is not in that two array. And job done.
My problem is, it seems quite inefficiency, how can i improve it? (Perferable if using some famous algorithm)
Thank you.
// get all duplicate input and store in an array
for ($row = 1; $row <= $highestRow; $row++) {
for ($y = 0; $y < $highestColumn; $y++) {
$val = $sheet->getCellByColumnAndRow($y, $row)->getValue();
//use reg exp to check whether it is valid
if ($y == $mailColumn && !preg_match($pattern,$val))
{$invaild[]=$row;}
//if valid, test whether it is duplicate
elseif ($y == $mailColumn && in_array($val,$email))
{$duplicate[]=$val;
$duplicate[]=$row;}
if ($y == $mailColumn)
{$email[]=$val;
$email=array_unique($email);}
}
}
// unique invalid array since i just need invalid inputs, not the invalid + duplicate input
$invaild=array_unique($invaild);
try this:
<?php
echo "<pre>";
$array1 = array("a#b.com","c","c","d#e.com","test1","","test3","test2","test3");
$array_no_mistake = array_filter($array1,function($subject){if(trim($subject)=="") return true;});
$array_uniq = array_diff(array_unique($array1),$array_no_mistake);
$array_dups = array_diff_assoc(array_diff($array1,$array_no_mistake),$array_uniq);
$array_valid = array_filter($array_uniq,function($subject){
if (preg_match('/\A(?:[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\Z/i', $subject)) {
return true;
} else {
return false;
}
});
$array_invalid = array_diff_assoc($array_uniq,$array_valid);
print_r($array1);
print_r($array_no_mistake);
print_r($array_uniq);
print_r($array_dups);
print_r($array_valid);
print_r($array_invalid);
?>
1) It would seem you are only interested in the email columns so i think there is no point in iterating over all of the other columns (so the inner loop is basically redundant).
2) You can use associative arrays in order to store emails as indexes and later on efficiently look for duplicates by checking for the existence of the index/email in the array.
Here's an example:
$valid = array();
$invalid = array();
$dups = array();
for ( $row = 0; $row < $highestRow; $row++ )
{
$email = $sheet->getCellByColumnAndRow( $mailColumn, $row )->getValue();
if ( !preg_match( $pattern, $email ) )
{
$invalid[] = $row;
}
else if ( isset( $dups[ $email ] ) )
{
$dups[ $email ][] = $row;
}
else
{
$dups[ $email ] = array();
$valid[] = $row
}
}
At the end of this, $invalid will hold a list of all of the invalid rows, $dups will hold an array of arrays, each indicating the rows in which the current email is the index and its value is an array which lists the rows that share this email. If the array at a certain index is empty, the email is not duplicated.
$valid will hold the numbers of the valid rows.
Now fancy algorithm, sorry...