Compare each multidimensional array value to all values in second multidimensional array? - php

Im a bit new here, Thanks for the help in advance.
I got 2 Multidimensional Arrays in PHP
Both pretty much look like this one:
Array
(
[0] => Array
(
[0] => 1
[Id] => 1
[1] => Soldier
[Name] => Soldier
[2] => 100
[Hitpoints] => 100
[3] => 15
[Attack] => 15
[4] => 50
[Speed] => 50
[5] => 50
[Range] => 50
[Total Units] => 511
[Combined Damage] => 7588.35
[Combined Hitpoints] => 51100
[Position] => 50
)
[1] => Array
(
[0] => 2
[Id] => 2
[1] => Sniper
[Name] => Sniper
[2] => 20
[Hitpoints] => 20
[3] => 50
[Attack] => 50
[4] => 20
[Speed] => 20
[5] => 300
[Range] => 0
[Total Units] => 0
[Combined Damage] => 0
[Combined Hitpoints] => 0
[Position] => 50
)
)
The arrays names are:
$Attackers
$Defenders
I need to compare values from $Attackers[*]['Position'] with $Defenders[*]['Position'].
I did make this loop but my problem is, that it only checks the same Index count to eachother. I need to check the $Attackers[0] to all $Defender indexes, then $Attackers[1] to all $Defender indexes, and so on.
Heres my original code that works, but only checks against the same index.
for($rowcount=0;$rowcount<count($Attackers);$rowcount++){
if (isset($Attackers[$rowcount]['Range']) && $Attackers[$rowcount]['Range'] != 0) {
if (($Attackers[$rowcount]['Position'] + $Defenders[$rowcount]['Position']) < $Attackers[$rowcount]['Range']) {
echo "within range, ATTACK";
} else {
echo "Before: " . $Attackers[$rowcount]['Position'] . "<br>";
$Attackers[$rowcount]['Position'] = $Attackers[$rowcount]['Position'] - $Attackers[$rowcount]['Speed'];
echo "After: " . $Attackers[$rowcount]['Position'] . "<br>";
}
}
}
I hope this is enough information.
Regards
Jesper

Doing this kind of check is pretty horrific and not scalable...
You would possibly benefit from having a map of positions. You could then simplify by observing events and applying outcomes.
class GameMap implements SplObserver
{
private $positions;
public function __construct($xSize, $ySize)
{
$this->positions = array();
for ($x = 0; $x < $xSize; $x++) {
$this->positions[$x] = array();
for ($y = 0; $y < $ySize; $y++) {
$this->positions[$x][$y] = new MapPosition($x, $y);
}
}
}
public function update(SplSubject $subject)
{
switch ($subject->getAction($this)) {
case "attack":
$positions = $this->getPositionsInRange($subject);
foreach ($positions as $position) {
$position->defend($subject);
}
break;
}
}
private function getPositionsInRange(Soldier $soldier)
{
$inRange = array();
$position = $soldier->getPosition();
$range = $soldier->range;
for ($x = ($position->coord["x"] - $range); $x < ($position->coord["x"] + $range); $x++) {
for ($y = ($position->coord["y"] - $range); $y < ($position->coord["y"] + $range); $y++) {
if (isset($this->positions[$x][$y])) {
$inRange[] = $this->positions[$x][$y];
}
}
}
return $inRange;
}
public function __get($key)
{
return isset($this->$key) ? $this->$key : null;
}
}
class MapPosition
{
private $coords = array();
private $players;
public function __construct($x, $y)
{
$this->coords["x"] = $x;
$this->coords["y"] = $y;
$this->players = new SplObjectStorage();
}
public function enter(Soldier $player)
{
$this->players->attach($player);
return $this;
}
public function leave(Soldier $player)
{
$this->players->detach($player);
return $this;
}
public function defend(Soldier $soldier)
{
foreach($this->players as $player)
{
$player->defend($soldier);
}
}
public function __get($key)
{
return isset($this->$key) ? $this->$key : null;
}
}
class Soldier implements SplSubject
{
private $id;
private $name;
private $hitPoints;
private $health;
private $attack;
private $speed;
private $range;
private $observers;
private $action;
private $position;
public function __construct($soldierData)
{
$this->id = $soldierData["id"];
$this->name = $soldierData["name"];
$this->hitPoints = $soldierData["hit_points"];
$this->health = $soldierData["health"];
$this->attack = $soldierData["attack"];
$this->speed = $soldierData["speed"];
$this->range = $soldierData["range"];
$this->observers = new SplObjectStorage();
}
public function attach(SplObserver $observer)
{
$this->observers->attach($observer);
}
public function detach(SplObserver $observer)
{
$this->observers->detach($observer);
}
public function notify()
{
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
public function getAction($observer)
{
return $this->observers->contains($observer) ? $this->action : null;
}
public function setPosition(MapPosition $position)
{
$this->postion = $position;
}
public function getPosition()
{
return $this->position;
}
public function attack()
{
$this->action = "attack";
$this->notify();
}
public function defend(Soldier $soldier)
{
$this->health -= $soldier->attack;
}
public function __get($key)
{
return isset($this->$key) ? $this->$key : null;
}
}
$s1 = new Soldier(array(
"id" => 1,
"name" => 'Sniper',
"hit_points" => 1000,
"health" => 100,
"attack" => 20,
"speed" => 5,
"range" => 10
));
$s2 = new Soldier(array(
"id" => 1,
"name" => 'Medic',
"hit_points" => 10000,
"health" => 100,
"attack" => 4,
"speed" => 10,
"range" => 1
));
$s3 = new Soldier(array(
"id" => 1,
"name" => 'Private',
"hit_points" => 5000,
"health" => 100,
"attack" => 10,
"speed" => 15,
"range" => 3
));
$a1 = new Soldier(array(
"id" => 1,
"name" => 'Sniper',
"hit_points" => 1000,
"health" => 100,
"attack" => 20,
"speed" => 5,
"range" => 15
));
$a2 = new Soldier(array(
"id" => 1,
"name" => 'Medic',
"hit_points" => 10000,
"health" => 100,
"attack" => 4,
"speed" => 10,
"range" => 1
));
$a3 = new Soldier(array(
"id" => 1,
"name" => 'Private',
"hit_points" => 5000,
"health" => 100,
"attack" => 10,
"speed" => 15,
"range" => 3
));
$map = new GameMap(20, 20);
$s1->attach($map);
$s2->attach($map);
$s3->attach($map);
$a1->attach($map);
$a2->attach($map);
$a3->attach($map);
$map->positions[0][0]->enter($a1)->enter($a2)->enter($a3);
$map->positions[9][9]->enter($s1)->enter($s2)->enter($s3);
var_dump($s1->health, $s2->health, $s3->health);
$a1->attack();
var_dump($s1->health, $s2->health, $s3->health);
$map->positions[9][9]->leave($s3);
$map->positions[19][19]->enter($s3);
$a1->attack();
var_dump($s1->health, $s2->health, $s3->health);
There is lots and lots of room for improvement here but hopefully you can see that you don't need to do all this checking. A soldier can attack, the attack notifies the map and the map checks which positions are in range of the attack. The positions then call the defend method of any soldiers in that position. The soldier defending then has their health reduced by the attack amount.
As I said LOADS of room for improvement like introducing sides and making sure no friendly fire kills can happen. Improve movement by applying move methods to Soldiers and they could then trigger leave/enter events on MapPositions (making the MapPosition an observer of the soldier too perhaps).
The main point though is that this looping is not really necessary and would suffer in scaling. Better design of your app will reap its own rewards...

You need to use nested for loops to check all the defenders positions versus one attackers position.
Something like this should get you started.
for($rowcount=0;$rowcount<count($Attackers);$rowcount++){
for($defrowcount=0; $defrowcount<count($Defenders); $defrowcount++){
if (isset($Attackers[$rowcount]['Range']) && $Attackers[$rowcount]['Range'] != 0) {
if (($Attackers[$rowcount]['Position'] + $Defenders[$defrowcount]['Position']) < $Attackers[$rowcount]['Range']) {
echo "within range, ATTACK";
} else {
echo "Before: " . $Attackers[$rowcount]['Position'] . "<br>";
$Attackers[$rowcount]['Position'] = $Attackers[$rowcount]['Position'] - $Attackers[$rowcount]['Speed'];
echo "After: " . $Attackers[$rowcount]['Position'] . "<br>";
}
}
}
}

Related

I get a 504 timeout error when importing excel to a db (Laravel)

I'm trying to import 10,000 records in excel with the library "Maatwebsite / Laravel-Excel" in Laravel, but when importing 10,000 records, the page returns a 504 timeout error (the odd thing is that it keeps inserting data in the db after that). Well then, I show you my code to see if you can help me, thanks.
This is the Import Inventory, where I programmed everything I should do with the data to be imported into the db.
class InventarioImport implements ToCollection, WithChunkReading
{
use Importable;
/**
* #param array $row
*
* #return User|null
*/
public function chunkSize(): int
{
return 250;
}
public function collection(collection $rows)
{
foreach ($rows as $row)
{
$almacenes = Almacen::where('tienda_id', \Session::get('tienda_id'))->get();
$codigos = Codigo::where('tienda_id', \Session::get('tienda_id'))->get();
$contc=-1;
$conta=0;
foreach ($codigos as $codigo) {
$contc++;
}
foreach ($almacenes as $almacen) {
$conta++;
}
if($row[$contc+1]=="DESCRIPCION") {
continue 1;
}
$idmarca = Marca::where('nombre_marca', $row[$contc+2])->where('tienda_id', \Session::get('tienda_id'))->first();
if ($idmarca==null) {
$marcaid= Marca::create([
'nombre_marca' => $row[$contc+2],
'tienda_id' => \Session::get('tienda_id'),
'estado' => "A",
])->id;
}
else {
$marcaid = $idmarca->id;
}
$buscarcategoria = Categoria::where('nombre_categoria', $row[$contc+3])->where('tienda_id', \Session::get('tienda_id'))->first();
if ($buscarcategoria==null) {
Categoria::create([
'nombre_categoria' => $row[$contc+3],
'tienda_id' => \Session::get('tienda_id'),
'estado' => "A",
]);
}
$i=0;
$buscaritem = Item::where('nombre_item', $row[$contc+1])->where('tienda_id', \Session::get('tienda_id'))->first();
$buscarunidad = Unidad::where('nombre_unidad', $row[$contc+4])->first();
$buscarmoneda = ConfiguracionMoneda::where('abreviacion_moneda', $row[$conta+3+$contc+4])->where('tienda_id', \Session::get('tienda_id'))->first();
$itemid= Item::create([
'marca_id' => $marcaid,
'nombre_item' => $row[$contc+1],
'unidad_id' => $buscarunidad->id,
'stock_minimo' => $row[$conta+1+$contc+4],
'stock_maximo' => $row[$conta+2+$contc+4],
'moneda_id' => $buscarmoneda->id,
'precio' => $row[$conta+4+$contc+4],
'impuesto' => $row[$conta+5+$contc+4],
'margen_final' => $row[$conta+6+$contc+4],
'margen_inicio' => $row[$conta+7+$contc+4],
'notas' => $row[$conta+8+$contc+4],
'estado' => "A",
'tienda_id' => \Session::get('tienda_id'),
])->id;
$a=$contc+4;
$j=$a+1;
foreach ($almacenes as $almacen) {
$buscaralmacen = Almacen::where('nombre_almacen', $almacen->nombre_almacen)->where('tienda_id', \Session::get('tienda_id'))->first();
ItemStock::create([
'item_id' => $itemid,
'almacen_id' => $buscaralmacen->id,
'detalle' => "Saldo Inicial",
'cantidad' => $row[$j],
'tipo' => "M",
'tienda_id' => \Session::get('tienda_id'),
'estado' => "A",
]);
$kardex = new Kardex();
$kardex->item_id = $itemid;
$kardex->fecha = date("Y/m/d");
$kardex->operacion = "Inicial";
$kardex->tipo = "";
$kardex->serie = "";
$kardex->numero = "";
$kardex->almacen_id = $buscaralmacen->id;
$kardex->tienda_id = \Session::get('tienda_id');
$kardex->saldocantidad = $row[$j];
$kardex->saldocosto = $row[$conta+4+$contc+4];
$kardex->saldototal = $row[$conta+4+$contc+4]*$row[$j];
$kardex->save();
$j++;
}
foreach ($codigos as $codigo) {
$buscarcodigo = Codigo::where('nombre_codigo', $codigo->nombre_codigo)->where('tienda_id', \Session::get('tienda_id'))->first();
$buscaritem = Item::where('nombre_item', $row[$contc+1])->where('tienda_id', \Session::get('tienda_id'))->first();
ItemCodigo::create([
'item_codigo' => $row[$i],
'codigo_id' => $buscarcodigo->id,
'item_id' => $buscaritem->id,
'tienda_id' => \Session::get('tienda_id'),
'estado' => "A",
]);
$i++;
}
}
}
}
This is my function in Controller, which I do the import as indicated in the previous script.
public function subirinventario(Request $request)
{
$title = 'Inventario subido';
$contarr= $request->contarr;
$arrayitems = Excel::import(new InventarioImport, $request->path);
return view('item.finalizar', compact('contarr','title'));
}
That would be all, I missed the routes and the views, but it works fine with few records, I have to emphasize that I have increased the runtime of nginx, restarted and nothing.
This is an image with the preview of the data and columns, only 10 are shown, but more than 10 thousand were detected.
You can try to put this 2 lines in the start of your method/function:
ini_set('memory_limit','1024M');
set_time_limit(3000000); //You can use 0 to remove limits
As I stated above you can use 0 inside the set_time_limit method, but i don't recommend this, because losing all the control of your execution is not worth in most cases
Hope it works!

PHP assigning numeric values to strings in an array

Hi everyone I am new to PHP, and would appreciate some of your help
I am currently building a black Jack Game, and need some help with how the Values of an array are displayed in a browser, I currently have the array for the Cards set like this:
private $suits = array('Clubs', 'Diamonds', 'Hearts', 'Spades');
private $cards = array(
'Ace'=> 1,
2 => 2,
3 => 3,
4 => 4,
5 => 5,
6 => 6,
7 => 7,
8 => 8,
9 => 9,
10 => 10,
'Jack' => 10,
'Queen'=>10,
'King'=>10);
It does what it is suppose to do and does the math how it should. It gives the Jack, Queen, and king the values it should so if a King is paired with a seven it will add 17. My problem with this is that in the browser the Jack, Queen, and King, are displayed as "10" instead of being displayed with the string, so it looks like they are not being accounted for. I would like to know if there is a way to have the string displayed instead without loosing the numeric value. I tried inverting like so
10 => 'King',
And by doing this King gets displayed but the numeric value is not accounted, so a person with a 7 will beat a person with a King.
Any help will be greatly appreciated... Thanks
EDIT *
I am adding in the full code, there are four different php files.
Card.php
class Card
{
private $suit;
private $figure;
public function __construct($Suit, $Fig) {
$this->suit = $Suit;
$this->figure = $Fig;
}
public function __toString() {
return $this->figure . ' of ' . $this->suit;
}
public function getFigure() {
return $this->figure;
}
public function getCard() {
echo $this->figure . " of " . $this->suit . ".<br />";
}
}
Deck.php
abstract class Deck
{
protected $arrCards;
protected $listOfCards;
/* abstract methods force classes that extends this class to implement them */
abstract public function dealCard(); //all classes that will inherit will inherit this method
/* already implemented methods */
public function __construct($Cards) {
$this->arrCards = $Cards;
}
public function shuffleCards() {
shuffle($this->arrCards);
}
public function listCards() {
foreach($this->arrCards as $Card) {
echo $Card . '<br />';
}
}
}
EnglishDeck.php
include_once "Deck.php";
include_once "Card.php";
class EnglishDeck extends Deck
{
private $suits = array('Clubs', 'Diamonds', 'Hearts', 'Spades');
private $cards = array(
1=> 'Ace',
2=> '2' ,
3 => '3',
4 => '4',
5=> '5' ,
6 => '6',
7 => '7',
8=> '8' ,
9 => '9',
10 => '10',
10 =>'Jack',
10=>'Queen',
10=>'King'
);
public function dealCard() {
return array_pop($this->arrCards);
}
public function __construct() {
$Cards = $this->initEnglishDeck();
parent::__construct($Cards);
}
function initEnglishDeck() {
$arrCards = array();
foreach($this->suits as $Suit) {
foreach ($this->cards as $Card) {
$arrCards[] = new Card($Suit, $Card);
}
}
return $arrCards;
}
}
cardgame.php
include_once "Card.php";
include_once "EnglishDeck.php";
$oBaraja = new EnglishDeck();
$oBaraja->shuffleCards();
//PLAYER 1
$oP1card1 = $oBaraja->dealCard();
echo("Player one has " . $oP1card1);
$oP1card2 = $oBaraja->dealCard();
echo(" and a " . $oP1card2 );
echo "<br>";
//PLAYER 2
$oP2card1 = $oBaraja->dealCard();
echo("Player two has " . $oP2card1);
$oP2card2 = $oBaraja->dealCard();
echo(" and a " . $oP2card2);
//Player Variables when cards are added together
$oPlayer1 = (string)$oP1card1 + (string)$oP1card2;
$oPlayer2 = (string)$oP2card1 + (string)$oP2card2;
echo "<br />";
if($oPlayer1 > $oPlayer2){
echo "Player 1 wins";
} else if ($oPlayer1 < $oPlayer2) {
echo "Player 2 wins";
} else {
echo "it's a tie";
}
This will display in a browser like so:
Player one has 10 of Hearts and a 2 of Clubs
Player two has 10 of Hearts and a 3 of Hearts
Player 2 wins
The problem is one of the 10's should have been a king/queen/jack
You have multiple options for doing that. I suggest to build a 2D array like:
$this->cards = array(
'k' => array('name' => 'King', 'value' => 10),
'q' => array('name' => 'Queen', 'value' => 10),
'a' => array('name' => 'Ace', 'value' => 1),
5 => array('name' => '5', 'value' => 5)
/* and so on */
);
Then you can get name and value easily with:
$this->cards['k']['name']; // Label of the card "King" (King)
$this->cards['a']['value']; // Value of the card "Ace" (1)
You store the keys of the cards and if you like to display the name you use $this->cards['{the_key}']['name'] and if you want to display the value or calculate with it use $this->cards['{the_key}']['value'].

Can't find the error behind the undefined index

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.

Finding the best-fit object from an array of objects

Given an array in the following structure (although obviously with many more items in it):
Array
(
[0] => stdClass Object
(
[currency] => 1
[role] => 3
[client_company] =>
[client_group] =>
[hourly_rate] => 115.00
)
[1] => stdClass Object
(
[currency] => 1
[role] => 1
[client_company] =>
[client_group] =>
[hourly_rate] => 115.00
)
[2] => stdClass Object
(
[currency] => 1
[role] => 3
[client_company] => 58
[client_group] =>
[hourly_rate] => 110.00
)
)
I'm trying to create a function that will take four parameters:
$role
$currency
$company [optional]
$group [optional]
("groups" are children of "companies": if a group is specified, a parent company will always also be specified)
...and that will return the "hourly rate" value from the item that best fits those parameters, on the basis that:
if $row, $currency, $company and $group are specified:
find a rate that matches the role, currency, company and group.
if there isn't one, find one that matches the role, currency and company
if there isn't one, find one that matches the role and currency
if there isn't one, return FALSE
if just $row, $currency and $company are specified:
find a rate that matches the role, currency and company
if there isn't one, find one that matches the role and currency
if there isn't one, return FALSE
if just $row and $currency are specified:
find a rate that matches the role and currency
if there isn't one, return FALSE
What I've got is below, and it works. However, it's ugly as sin. There must be a more elegant way than just bashing a load of if/else and loops together. However, it's Friday and I've had too much pizza for lunch and my brain has become ensludged with cheese.
Can you help?
$hourly_rate = FALSE;
if ( !empty($group) && !empty($company) ) {
foreach ( $rates_cache as $rate ) {
if ( $rate->currency == $currency && $rate->role == $role && (int) $rate->client_company === (int) $company && (int) $rate->client_group === (int) $group ) {
$hourly_rate = $rate->hourly_rate;
}
}
if ( empty($hourly_rate) ) {
foreach ( $rates_cache as $rate ) {
if ( $rate->currency == $currency && $rate->role == $role && (int) $rate->client_company === (int) $company ) {
$hourly_rate = $rate->hourly_rate;
}
}
}
if ( empty($hourly_rate) ) {
foreach ( $rates_cache as $rate ) {
if ( $rate->currency == $currency && $rate->role == $role ) {
$hourly_rate = $rate->hourly_rate;
}
}
}
}else if ( !empty($company) ) {
foreach ( $rates_cache as $rate ) {
if ( $rate->currency == $currency && $rate->role == $role && (int) $rate->client_company === (int) $company ) {
$hourly_rate = $rate->hourly_rate;
}
}
if ( empty($hourly_rate) ) {
foreach ( $rates_cache as $rate ) {
if ( $rate->currency == $currency && $rate->role == $role ) {
$hourly_rate = $rate->hourly_rate;
}
}
}
}else{
foreach ( $rates_cache as $rate ) {
if ( $rate->currency == $currency && $rate->role == $role ) {
$hourly_rate = $rate->hourly_rate;
}
}
}
return $hourly_rate;
Assumption
I believe your cache is always in the format below
Cache Format:
$cache = array(
0 => (object) (array(
'currency' => 1,
'role' => 3,
'client_company' => '',
'client_group' => '',
'hourly_rate' => '115.00'
)),
1 => (object) (array(
'currency' => 1,
'role' => 1,
'client_company' => '',
'client_group' => '',
'hourly_rate' => '115.00'
)),
2 => (object) (array(
'currency' => 1,
'role' => 3,
'client_company' => 58,
'client_group' => '',
'hourly_rate' => '110.00'
))
);
Your Revised Function
$param = array(
"role" => 1,
"currency" => 1
);
echo find($cache, $param)->hourly_rate;
Function Used
function find($cache, $param) {
$mx = array();
if (! isset($param['role']) || ! isset($param['currency']))
throw new Exception("Missing Role Or Currency");
foreach ( $cache as $k => $r ) {
foreach ( array_keys(array_intersect($param, (array) $r)) as $key ) {
if ($r->{$key} == $param[$key]) {
isset($mx[$k]) ? $mx[$k] ++ : $mx[$k] = 1;
}
}
}
arsort($mx);
return $cache[key($mx)];
}
More Complex: Another Approach
Usage
$param = array(
"role" => 1,
"currency" => 1
);
$process = new Process($cache);
echo $process->find($param)->best()->hourly_rate; // Outputs 115.00
Multiple Results
When find best fit .. there is possibility you would get more than one result
$param = array(
"role" => 3,
"currency" => 1
);
$process = new Process($cache);
var_dump($process->find($param)->results());
Output
array (size=2)
0 =>
object(stdClass)[1]
public 'currency' => int 1
public 'role' => int 3
public 'client_company' => string '' (length=0)
public 'client_group' => string '' (length=0)
public 'hourly_rate' => string '115.00' (length=6)
2 =>
object(stdClass)[3]
public 'currency' => int 1
public 'role' => int 3
public 'client_company' => int 58
public 'client_group' => string '' (length=0)
public 'hourly_rate' => string '110.00' (length=6)
Not getting best result
You can see based on your parameters you are getting 2 if you are looking for cheapest prize and you call
$param = array(
"role" => 3,
"currency" => 1
);
echo Process::quick($cache, $param)->best()->hourly_rate; // returns 115.00 but that is not the cheapest
Resolution
The solution is you can add filter and sort
$param = array(
"role" => 3,
"currency" => 1
);
$sort = function ($a, $b) {
return $a->hourly_rate < $b->hourly_rate ? - 1 : 1;
};
echo Process::quick($cache, $param)->sort($sort)->best()->hourly_rate; // 110
Getting all Related
You can also just loop through all the result and select the columns you want insted of just getting best result
foreach ( Process::quick($cache, $param)->sort($sort)->getColoum("client_company", "hourly_rate") as $result ) {
print_r($result);
}
Output
stdClass Object
(
[client_company] => 58
[hourly_rate] => 110.00
)
stdClass Object
(
[client_company] =>
[hourly_rate] => 115.00
)
Updated Class
To add all this additional functions you need to upgrade your class to
class Process implements JsonSerializable, IteratorAggregate {
private $cache;
private $matrix = array();
private $final = array();
function __construct($cache) {
$this->cache = $cache;
}
function find($param) {
if (! isset($param['role']) || ! isset($param['currency']))
throw new Exception("Missing Role Or Currency");
foreach ( $this->cache as $k => $rate ) {
$keys = array_intersect($param, (array) $rate);
foreach ( array_keys($keys) as $key ) {
if ($rate->{$key} == $param[$key]) {
isset($this->matrix[$k]) ? $this->matrix[$k] ++ : $this->matrix[$k] = 1;
}
}
}
arsort($this->matrix);
$this->matrix = array_keys(array_filter($this->matrix, function ($v) {
return $v >= 2;
}));
$this->final = $this->sortArray($this->cache, $this->matrix);
return $this;
}
public static function quick($cache, $param) {
$process = new Process($cache);
return $process->find($param);
}
public function best() {
reset($this->final);
return empty($this->final) ? : current($this->final);
}
public function results() {
return $this->final;
}
public function limit($length = 0) {
$this->final = array_slice($this->final, 0, $length);
return $this;
}
public function sort(Callable $function) {
usort($this->final, $function);
return $this;
}
public function getColoum() {
$arg = array_flip(func_get_args());
foreach ( $this->final as &$s ) {
foreach ( $s as $k => $v ) {
if (! isset($arg[$k]))
unset($s->{$k});
}
}
return $this;
}
public function getIterator() {
return new ArrayIterator($this->final);
}
public function jsonSerialize() {
return json_encode($this->final);
}
public function __toString() {
return $this->jsonSerialize();
}
private function sortArray(array $array, array $orderArray) {
$ordered = array();
foreach ( $orderArray as $key => $value ) {
array_key_exists($value, $array) and $ordered[$value] = $array[$value];
}
return $ordered;
}
}

Array structure for Shopping Basket

I am trying to implement multidimensional array that hold data of Pizza id's with options and extras id's.
Let look at the following scenario...
Customer wants
Two 'Chicken Pizza' (ProductID:12) - '10 inches' (OptionsID:4) with extras of Ham and Tuna (ExtrasID: 5,10)
One 'Chicken Pizza' (ProductID:12) - '10 inches' (OptionsID:4) with extras of Sweet Corn (ExtrasID: 2)
One 'Chicken Pizza' (ProductID:12) - '14 inches' (OptionsID:2) with no extras
Eleven 'Vegetarian Pizza' (ProductID:35) - '7 inches' (OptionsID:52) with no extras
See the following code below that match the scenario... Im I doing it right? or what can be done to improve it and readable?
//Two 'Chicken Pizza' (ProductID:12) - '10 inches' (OptionsID:4)
//With extras of Ham and Tuna (ExtrasID: 5,10)
$option4[] = array(
'quantity' => 2,
'extras_id' => array(5, 10)
);
//One 'Chicken Pizza' (ProductID:12) - '10 inches' (OptionsID:4)
//With extras of Sweet Corn (ExtrasID: 2)
$option4[] = array(
'quantity' => 1,
'extras_id' => array(2)
);
//One 'Chicken Pizza' (ProductID:12) - '14 inches' (OptionsID:2)
//With no extras
$option2[] = array(
'quantity' => 1,
'extras_id' => array()
);
//Eleven 'Vegetarian Pizza' (ProductID:35) - '7 inches' (OptionsID:52)
//With no extras
$option52[] = array(
'quantity' => 11,
'extras_id' => array()
);
//Hold data of Customer Orders
$shoppingBasket = array(
"ShopID_24" => array(
'ProductID' => array(
'12' => array(
'OptionID' => array(
'4' => $option4,
'2' => $option2
)
),
'35' => array(
'OptionID' => array(
'52' => $option52
)
),
)
)
);
echo "<pre>";
print_r($shoppingBasket);
echo "</pre>";
print_r output:
Array
(
[ShopID_24] => Array
(
[ProductID] => Array
(
[12] => Array
(
[OptionID] => Array
(
[4] => Array
(
[0] => Array
(
[quantity] => 2
[extras_id] => Array
(
[0] => 5
[1] => 10
)
)
[1] => Array
(
[quantity] => 1
[extras_id] => Array
(
[0] => 2
)
)
)
[2] => Array
(
[0] => Array
(
[quantity] => 1
[extras_id] => Array ()
)
)
)
)
[35] => Array
(
[OptionID] => Array
(
[52] => Array
(
[0] => Array
(
[quantity] => 11
[extras_id] => Array ()
)
)
)
)
)
)
)
I would consider doing this by modeling the same data in a few custom PHP objects. In this case you might have a shop object with products, and product objects with options. This is really quick off the top of my head:
class Shop {
private $_products = array();
public function getProducts()
{ return $this->_products;}
public function addProduct(Product $product)
{ $this->_products[] = $product;
return $this;
}
}
class Product {
private $_options = array();
public function getOptions()
{ return $this->_options; }
public function addOption(Option $option)
{ $this->_options[] = $option;
return $this;
}
}
class Option {
private $_optionKey;
private $_optionValue;
public function getKey()
{ return $this->_optionKey; }
public function getKey()
{ return $this->_optionValue; }
public function setOption($key, $value)
{
$this->_optionKey = $key;
$this->_optionValue = $value;
return $this;
}
}
What does this get you? For starters, you can define limits and parameters to what you can store in this, while with the nested array that you are using, there is absolutely no enforcement of structure or value. You can also define other methods that allow you to actually DO things with these bits of data.
If you absolutely MUST have an array version of these, you can implement something like a toArray() method in each of these that will convert the objects into an array to be consumed by some other bit of code. You might also consider reading up on a few interfaces such as iterator and countable in the PHP manual.
You set up one array on the beginning, fine. Now use it in the right way.
$option['ShopID_'.$id]; //where $id is obviusly the id number;
Now fill the $option array with the orders.
$option['ShopID_'.$id]['ProductId_'.$pid][] = array(
'quantity' => 1,
'extras_id' => array(2), //maybe a string is enough here (?) (e.g. '2,5,etc..')
'inches' => $inches
);
$pid is obviusly the pizza Id you are searching for..
as well this is just a "static" example!
I recommend you to use OO programming, this saves you a lot of headache!
Try something like this:
<?php
class Extra
{
var $id;
var $name;
var $amount;
function __construct()
{
$this->id = 0;
$this->name = '';
$this->amount = 0;
}
}
class Option
{
var $id;
var $name;
function __construct()
{
$this->id = 0;
$this->name = '';
}
}
class Pizza
{
var $id;
var $name;
var $options;
var $extras;
function __construct()
{
$this->id = 0;
$this->name = '';
$this->options = array();
$this->extras = array();
}
}
?>
And to test it:
<?php
$pizzas = array();
for($i=0; $i<10; $i++)
{
$pizza = new Pizza();
$pizza->id = $i;
$pizza->name = 'Pizza '.$i;
for($j=0; $j<$i; $j++)
{
$option = new Option();
$option->id = $j;
$option->name = 'Option '.$j;
$pizza->options[] = $option;
}
for($k=$i; $k>0; $k--)
{
$extra = new Extra();
$extra->id = $k;
$extra->name = 'Extra '.$k;
$extra->amount = $k;
$pizza->extras[] = $extra;
}
$pizzas[] = $pizza;
}
print_r($pizzas);
?>
Good luck :)

Categories