I have the following code, and i keep getting undefined index error, the code is failing on test5() but i'm unable to find the error.
<?php
function test1() {
$vars = [0, 1, 2, 4, 3];
for ($i = 0; $i < count($vars); $i++) {
print $vars[$i] . "\n";
}
}
function test2() {
$flavors = ['vanilla', 'pistachio', 'banana', 'caramel', 'strawberry'];
$favorite = 'banana';
foreach ($flavors as $key => $flavor) {
if ($flavor === $favorite) {
print $key . "\n";
break;
}
}
}
function test3() {
$stuff = ['shoes', 33, null, false, true];
$selected = 0;
foreach ($stuff as $key => $thing) {
if ($thing == $selected) {
print $key . "\n";
break;
}
}
}
function test4() {
$four = 4;
$five = test4_helper($four);
print "four: $four\n";
print "five: $five\n";
}
function test4_helper(&$arg) {
$return = $arg++;
return $return;
}
function test5() {
$products = [
'Trek Fuel EX 8' => [
'price' => 2000,
'quantity' => 1
],
'Trek Remedy 9' => [
'price' => 2600,
'quantity' => 2
],
'Trek Scratch 8' => [
'price' => 3500,
'quantity' => 1
]
];
$total = 0;
$callback = function ($product, $name) {
//$total = 0;
$tax = 1.2;
$price = $product[$name]['price'];
$total += ($price * $product[$name]['quantity']) * $tax;
return $total;
};
array_walk($products, $callback);
print "$total\n";
}
/* * **********************************
* *** DO NOT EDIT BELOW THIS LINE ****
* *********************************** */
$tests = 5;
for ($i = 1; $i <= $tests; $i++) {
$function = "test$i";
print "\n\n==== Test $i ====\n";
$function();
print "==== END of test $i ====\n <br>";
}
what is the problem with this code?
it looks that it's failing on test 5
PHP closures are not like JavaScript ones in that they do not inherit the parent scope. You need to pass in any dependencies via the use construct. In your example...
$callback = function ($product, $name) use ($total) {
// etc
See http://php.net/manual/functions.anonymous.php#example-166
Arrays in PHP are defined like this:
$products = array(
'Trek Fuel EX 8' => array(
'price' => 2000,
'quantity' => 1
),
'Trek Remedy 9' => array(
'price' => 2600,
'quantity' => 2
),
'Trek Scratch 8' => array(
'price' => 3500,
'quantity' => 1
)
);
Which means you also need to look at $vars = [0, 1, 2, 4, 3]; and $flavors = ['vanilla', 'pistachio', 'banana', 'caramel', 'strawberry']; and fix them too.
Related
I'm trying to make a draw for a secret Santa.
I collect in a table the information of the person and the name of the person on whom it should not fall (to avoid couples).
However during my PHP loop I can't take into account my exclusions
foreach ($supplier as $sup){
$exclude = $sup['blacklist'];
$data = $recipient;
$temp = array_diff($data[], array($exclude));
echo $temp[rand(0, sizeOf($temp))];
foreach ($recipient as $key=>$recip){
if ($sup['surname'] !== $recip['surname']){
$result[] = ['recipient' => $recip, 'supplier' => $sup];
unset($recipient[$key]);
}
}
}
How can I take into account this blacklist please?
shuffle($supplier);
shuffle($recipient);
// dump($supplier, $recipient);
$result = [];
foreach ($supplier as $sup){
$assign = false;
dump($sup);
foreach ($recipient as $key=>$recip){
dump($recip['surname']);
if ($sup['surname'] !== $recip['surname'] && $sup['blacklist'] !== $recip['surname'] && $sup['surname'] !== $recip['blacklist']){
$result[] = ['recipient' => $recip, 'supplier' => $sup];
dump($sup['surname']);
unset($recipient[$key]);
$assign = true;
}
if ($assign === true){
break;
}
}
}
return $result;
}
this is my code with shuffle
Your solution is fine, but with that nested loop it's going to start behaving poorly as the list of participants grows. You can accomplish the task with a single array and two linear passes over it:
$people = [
[ 'name' => 'alice', 'blacklist' => ['bob'] ],
[ 'name' => 'bob', 'blacklist' => ['alice'] ],
[ 'name' => 'carl', 'blacklist' => ['david'] ],
[ 'name' => 'david', 'blacklist' => ['carl'] ],
[ 'name' => 'elise', 'blacklist' => ['frank'] ],
[ 'name' => 'frank', 'blacklist' => ['elise'] ],
[ 'name' => 'georg', 'blacklist' => ['herb'] ],
[ 'name' => 'herb', 'blacklist' => ['george'] ]
];
function wrap_index($count, $index) {
$cur = $index;
if( $index == 0 ) {
$prev = $count - 1;
$next = $index + 1;
} else if( $index == $count - 1) {
$prev = $index - 1;
$next = 0;
} else {
$prev = $index - 1;
$next = $index + 1;
}
return [$prev, $cur, $next];
}
function array_swap(&$array, $a, $b) {
$tmp = $array[$a];
$array[$a] = $array[$b];
$array[$b] = $tmp;
}
function santify($people) {
shuffle($people);
$count = count($people);
for( $i=0; $i<$count; ++$i ) {
list($prev, $cur, $next) = wrap_index($count, $i);
if( in_array($people[$cur]['name'], $people[$next]['blacklist']) ) {
printf("%s in blacklist for %s\n", $people[$cur]['name'], $people[$next]['name']);
array_swap($people, $cur, $prev);
}
}
$pairs = [];
for( $i=0; $i<$count; ++$i ) {
list($prev, $cur, $next) = wrap_index($count, $i);
$pairs[] = [ $people[$cur]['name'], $people[$next]['name'] ];
}
return $pairs;
}
foreach( santify($people) as $pair ) {
printf("%s\n", json_encode($pair));
}
Output:
david in blacklist for carl
elise in blacklist for frank
["david","georg"]
["georg","carl"]
["carl","bob"]
["bob","herb"]
["herb","elise"]
["elise","alice"]
["alice","frank"]
["frank","david"]
There is a caveat to this approach, though. It will only work with strict 1:1 blacklist arrangements. Once there is a love triangle [or quardrangle or above] or any polyamory, neither of our solutions is equipped for these extra dimensions.
I make a parser of items from DotA 2 user inventory in the Steam service. Every time I try to parse user data, I get an empty value:
{"success":true,"items":[]}, but there are items in my Steam inventory.
My function to parse items:
public function loadMyInventory() {
if(Auth::guest()) return ['success' => false];
$prices = json_decode(Storage::get('prices.txt'), true);
$response = json_decode(file_get_contents('https://steamcommunity.com/inventory/'.$this->user->steamid64.'/570/2?l=russian&count=5000'), true);
if(time() < (Session::get('InvUPD') + 5)) {
return [
'success' => false,
'msg' => 'Error, repeat in '.(Session::get('InvUPD') - time() + 5).' сек.',
'status' => 'error'
];
}
//return $response;
$inventory = [];
foreach($response['assets'] as $item) {
$find = 0;
foreach($response['descriptions'] as $descriptions) {
if($find == 0) {
if(($descriptions['classid'] == $item['classid']) && ($descriptions['instanceid'] == $item['instanceid'])) {
$find++;
# If we find the price of an item, then move on.
if(isset($prices[$descriptions['market_hash_name']])) {
# Search data
$price = $prices[$descriptions['market_hash_name']]*$this->config->curs;
$class = false;
$text = false;
if($price <= $this->config->min_dep_sum) {
$price = 0;
$text = 'Cheap';
$class = 'minPrice';
}
if(($descriptions['tradable'] == 0) || ($descriptions['marketable'] == 0)) {
$price = 0;
$class = 'minPrice';
$text = 'Not tradable';
}
# Adding to Array
$inventory[] = [
'name' => $descriptions['market_name'],
'price' => floor($price),
'color' => $this->getRarity($descriptions['tags']),
'tradable' => $descriptions['tradable'],
'class' => $class,
'text' => $text,
'classid' => $item['classid'],
'assetid' => $item['assetid'],
'instanceid' => $item['instanceid']
];
}
}
}
}
}
Session::put('InvUPD', (time() + 5));
return [
'success' => true,
'items' => $inventory
];
}
But should return approximately the following value:
{"success":true,"items":[{"classid":"2274725521","instanceid":"57949762","assetid":"18235196074","market_hash_name":"Full-Bore Bonanza","price":26}]}
Where my mistake?
First of all, you are iterating on descriptions for every assets, which is assets*descriptions iteration, it's quite a lot, but you can optimize this.
let's loop once for descriptions and assign classid and instanceid as object key.
$assets = $response["assets"];
$descriptions = $response["descriptions"];
$newDescriptions=[];
foreach($descriptions as $d){
$newDescriptions[$d["classid"]][$d["instanceid"]] = $d;
}
this will give as the ability to not loop over description each time, we can access the description of certain asset directly $newDescriptions[$classid][$instanceid]]
foreach($assets as $a){
if(isset($newDescriptions[$a["classid"]]) && isset($newDescriptions[$a["classid"]][$a["instanceid"]])){
$assetDescription = $newDescriptions[$a["classid"]][$a["instanceid"]];
$inventory = [];
if(isset($prices[$assetDescription["market_hash_name"]])){
$price = $prices[$assetDescription['market_hash_name']]["price"]*$this->config->curs;
$class = false;
$text = false;
if($price <= $this->config->min_dep_sum) {
$price = 0;
$text = 'Cheap';
$class = 'minPrice';
}
if(($assetDescription['tradable'] == 0) || ($assetDescription['marketable'] == 0)) {
$price = 0;
$class = 'minPrice';
$text = 'Not tradable';
}
$inventory["priceFound"][] = [
'name' => $assetDescription['market_name'],
'price' => floor($price),
'color' => $this->getRarity($assetDescription['tags']),
'tradable' => $assetDescription['tradable'],
'class' => $class,
'text' => $text,
'classid' => $a['classid'],
'assetid' => $a['assetid'],
'instanceid' => $a['instanceid']
];
}else{
$inventory["priceNotFound"][] = $assetDescription["market_hash_name"];
}
}
}
About your mistake:
are you Sure your "prices.txt" contains market_hash_name?
I don't see any other issue yet, operationg on the data you have provided in comment, I got print of variable $assetDescription. Please doublecheck variable $prices.
Simple question how can i transform this string:
"'One' => 1,'Two' => 2,'Three' => 3,'Four' => 4,"
To an array like this :
array['One'] = 1;
array['Two'] = 2;
array['Three'] = 3;
array['Four'] = 4;
Use regex and array_combine
preg_match_all('/\'(\w+)\'\s*=>\s*(\d+)/', $str, $m);
print_r(array_combine($m[1], $m[2]));
demo
$string = "'One' => 1,'Two' => 2,'Three' => 3,'Four' => 4,";
$array = explode(',',$string);
foreach($array as $item){
$new_items = explode(' => ', $item);
$key = $new_items[0];
$value = $new_items[1];
$new_array[][$key] = $value;
}
var_dump($new_array);
Here a tested solution:
$input = "'One' => 1,'Two' => 2,'Three' => 3,'Four' => 4,";
$gen = new ArrayGenerator($input);
$this->assertSame([
'One' => 1,
'Two' => 2,
'Three' => 3,
'Four' => 4,
], $gen->translate());
and here complete code
use PHPUnit\Framework\TestCase;
class FooTest extends TestCase
{
public function testItems()
{
$input = "'One' => 1,'Two' => 2,'Three' => 3,'Four' => 4,";
$parser = new Parser($input);
$this->assertEquals([
"'One' => 1",
"'Two' => 2",
"'Three' => 3",
"'Four' => 4"
], $parser->items());
}
public function testKeyValue()
{
$input = "'One' => 1";
$parser = new KeyValue($input);
$this->assertEquals([
"'One'",
"1",
], $parser->items());
}
public function testKeyValueWithoutQuotas()
{
$input = "'One' => 1";
$parser = new KeyValue($input);
$this->assertEquals([
"One",
"1",
], $parser->itemsWithoutQuotas());
}
public function test()
{
$input = "'One' => 1,'Two' => 2,'Three' => 3,'Four' => 4,";
$gen = new ArrayGenerator($input);
$this->assertSame([
'One' => 1,
'Two' => 2,
'Three' => 3,
'Four' => 4,
], $gen->translate());
}
}
class ArrayGenerator
{
private $input;
public function __construct(string $input)
{
$this->input = $input;
}
public function translate()
{
$parser = new Parser($this->input);
$parsed = $parser->items();
$trans = [];
foreach ($parsed as $item) {
$pair = new KeyValue($item);
$trans[$pair->itemsWithoutQuotas()[0]] = (int) $pair->itemsWithoutQuotas()[1];
}
return $trans;
}
}
class KeyValue
{
private $input;
public function __construct(string $input)
{
$this->input = $input;
}
public function items()
{
$exploded = explode(' => ', $this->input);
return $exploded;
}
public function itemsWithoutQuotas()
{
$items = $this->items();
foreach ($items as $key => $item) {
$items[$key] = str_replace("'", "", $item);
}
return $items;
}
}
class Parser
{
private $input;
public function __construct(string $input)
{
$this->input = $input;
}
public function items()
{
$exploded = explode(',', $this->input);
$exploded = array_filter($exploded, function ($item) {
return $item != "";
});
return $exploded;
}
}
You can simply use the php function array_flip:
array_flip — Exchanges all keys with their associated values in an
array
Warning on collision:
If a value has several occurrences, the latest key will be used as its
value, and all others will be lost.
Example #2 array_flip() example : collision
<?php
$input = array("a" => 1, "b" => 1, "c" => 2);
$flipped = array_flip($input);
print_r($flipped);
?>
The above example will output:
Array
(
[1] => b
[2] => c
)
I have this array:
$actualPlan = 'medium';
$plans = array(
array(
'plans' => array(
'tiny' => 29,
'small' => 69,
'medium' => 179,
'big' => 359
)
)
);
During a foreach, I display the contents of plans of this array like this:
foreach($plans as $key => $data) {
foreach($data['plans'] as $plan => $rate) {
...
}
}
But how can I know the position of the $actualPlan ?
For example, for :
if $actualPlan == medium it should return me 3.
if $actualPlan == tiny it should return me 1.
Thanks.
inside the loop:
echo array_search($actualPlan, array_keys($rate)); // returns the index position as int
here will output 1,2,3,4 for the inputs 'tiny','small','medium','big'
Within the foreach($plans as $key => $data) {, you could make the conditional like this :
$current_plan = explode('___', $actualPlan);
$current_key = array_search($current_plan[0],array_keys($data['plans']));
foreach($data['plans'] as $plan => $rate) {
$current_iterated_key = array_search($plan,array_keys($data['plans']));
if ($current_iterated_key < $current_key) {
echo "$plan => Downgrade\r\n";
} elseif ($current_iterated_key > $current_key) {
echo "$plan => Upgrade\r\n";
} elseif($current_iterated_key == $current_key) {
echo "$plan => Current\r\n";
}
}
In my lottery project I have 5 tickets, in which you select numbers and buy. The thing is, you can only buy the tickets if you buy them in order... For example:
Ticket 1 Ticket 2 Ticket 3 Ticket 4 Ticket 5
If you add numbers to the ticket 1 and then the others it works... If you skip the ticket 1 and add numbers to the other ones, when you try to buy you get this error:
ContextErrorException: Notice: Undefined offset: 0 in C:\wamp\www\Digidis\front\src\MediaparkLt\UserBundle\Service\MoneyManager.php line 313
The full stack:
array('cartProduct' => array('title' => 'EUROMILLONES', 'price' => '2.35', 'product' => '2', 'ticket_id' => '1433921783_19792', 'numbers' => '8,13,14,17,37', 'stars' => '4,7', 'betslip' => '{"duration":"1","subscription":"false","jsPrice":"235","type":"simple","numbers1":"0,0,0,0,0","numbers2":"8,13,14,17,37","numbers3":"0,0,0,0,0","numbers4":"0,0,0,0,0","numbers5":"0,0,0,0,0","stars1":"0,0","stars2":"4,7","stars3":"0,0","stars4":"0,0","stars5":"0,0","dayOfWeek":"3"}', 'is_syndicate' => false, 'draw' => object(DateTime)), 'product' => object(Product), 'user' => object(User), 'reference' => null, 'paymentResult' => 'Authorised', 'bets' => object(stdClass), 'individualBets' => array(), 'tickets' => array(array('numbers' => '8,13,14,17,37', 'stars' => '4,7')), 'k' => '0', 't' => array('numbers' => '0,0,0,0,0', 'stars' => '0,0'), 'is_ticket_filled' => false, 'week_id' => array(array('ticketId' => '7005')), 'g' => '0', 'lastId' => '7005', 'purchase' => object(Purchase), 'price' => '2.35', 'bet' => object(Bet), 'euromillonesBet' => object(EuromillonesBet), 'drawDate' => array(object(DrawDate)), 'j' => '0')) in C:\wamp\www\Digidis\front\src\MediaparkLt\UserBundle\Service\MoneyManager.php line 313
As you can see first it gets the ticket 1, which is empty(or 0) and thats why it causes the error... How can I make it so that it skips the empty tickets?
Here is the controller where the error occurs:
$bets = json_decode($cartProduct['betslip']);
$individualBets = array();
$tickets = array(
array('numbers' => $bets->numbers1, 'stars' => $bets->stars1),
array('numbers' => $bets->numbers2, 'stars' => $bets->stars2),
array('numbers' => $bets->numbers3, 'stars' => $bets->stars3),
array('numbers' => $bets->numbers4, 'stars' => $bets->stars4),
array('numbers' => $bets->numbers5, 'stars' => $bets->stars5)
);
if ($bets->type === 'simple') {
foreach ($tickets as $k => $t) {
$is_ticket_filled = ((int) str_replace(',', '', $t['numbers'])) > 0;
if (!$is_ticket_filled) {
unset($tickets[$k]);
}
}
} else if ($bets->type === 'multiple') {
$tickets = array(array('numbers' => $bets->numbers1, 'stars' => $bets->stars1));
}
$week_id = null;
for ($k = 0; $k < (count($tickets)); $k++) {
for ($g = 0; $g < $bets->duration; $g++) {
if (!isset($week_id[$g])) {
$week_id[$g] = $this->entityManager->getRepository('MediaparkLtLotteryBundle:Bet')->getLastTicketId();
if ($week_id[$g]) {
$week_id[$g]['ticketId'] ++;
} else {
$week_id[$g]['ticketId'] = 0;
}
}
$lastId = $week_id[$g]['ticketId'];
$purchase = new Purchase();
$purchase->setUser($user);
$purchase->setDrawDate($cartProduct['draw']);
$purchase->setProduct($product);
$purchase->setReference($reference);
$price = $cartProduct['price'];
$bet = new Bet();
if ('eurojackpot' == $product->getAlias()) {
$euromillonesBet = new EurojackpotBet();
} else {
$euromillonesBet = new EuromillonesBet();
}
$drawDate = $this->entityManager->getRepository('MediaparkLtLotteryBundle:DrawDate')->findByDrawDate($cartProduct['draw']);
if (!$drawDate)
die('no draw date found ' . $cartProduct['draw']->format('Y-m-d H:i:s'));
$bet->setDrawDate($drawDate[0]);
$bet->setTicketId($lastId);
if (strtoupper($paymentResult) === 'AUTHORISED') {
$bet->setStatus(BetStatus::AUTHORISED);
} else {
$bet->setStatus(BetStatus::FAILED);
}
$bet->setWinnings(0);
$euromillonesBet->setBet($bet);
/// LINE 313 ABOVE!!!!!!!
$numbers = $this->getNumbersArray($tickets[$k]['numbers']);
$j = 0;
foreach ($numbers as $number) {
$j++;
$name = 'setN' . $j;
$euromillonesBet->$name($number);
}
$numbers = $this->getNumbersArray($tickets[$k]['stars']);
$euromillonesBet->setS1($numbers[0]);
$euromillonesBet->setS2($numbers[1]);
$euromillonesBet->setAmountOfStars(Bet::NUMBER_OF_STARS);
$purchase->addBet($bet);
$purchase->setPricePaid($price);
if (strtoupper($paymentResult) === 'AUTHORISED') {
$purchase->setStatus(PaymentStatus::AUTHORISED);
} else {
$purchase->setStatus(PaymentStatus::FAILED);
}
if ($bets->subscription === "true") {
$contract = new PurchaseContract();
$contract->setAccumulatedWinnings(0);
$contract->setCancellationDate(null);
$contract->setFirstDrawDate($purchase->getDrawDate());
$contract->setLastRenewedDate($purchase->getDrawDate());
$contract->setNextRenewalFirstDrawDate($purchase->getDrawDate());
// $contract->setPurchase($purchase);
$contract->setStatusPurchaseContract(1);
$contract->setWeeks(1);
$purchase->setPurchaseContract($contract);
$this->entityManager->persist($contract);
}
if ($g == 0)
$individualBets[] = $euromillonesBet;
$this->entityManager->persist($bet);
$this->entityManager->persist($euromillonesBet);
$this->entityManager->persist($purchase);
$this->entityManager->flush();
}
}
return $individualBets;
}
From what I see the bet type in your object is set to "type":"simple" and numbers1":"0,0,0,0,0"
$is_ticket_filled = ((int) str_replace(',', '', $t['numbers'])) > 0;
//(int) 00000 = 0
if (!$is_ticket_filled) {
unset($tickets[$k]);
}
Is causing the issue since unset does not reset the array indexes.
http://ideone.com/5q74Wv
Then later you iterate using for($k=0; $k < count($tickets); $k++)
You should instead rebase the array after using unset($tickets[$k])
if ($bets->type === 'simple') {
//...
$tickets = array_values($tickets);
}
or check the existence of the ticket when iterating over indexes
$ticketCount = count($tickets);
for ($k=0; $k < $ticketCount; $k++) {
if (false === isset($tickets[$k]) {
continue;
}
//...
}
or easier still, iterate over the existing tickets array using foreach instead of for.
foreach ($tickets as $k => $ticket) {
//...
}
Then change $tickets[$k] with just $ticket since $k is not used anywhere else.