This question already has answers here:
Show a number to two decimal places
(25 answers)
Closed 8 years ago.
Hello I have a basic php script which is used to display the price of a group of items in an array. The array has 3 pieces of information: name, price, and sku. The price could be set to something like 99.95, 12.95, 10.50 or just 5.00. Everything seems to work well so far, but when I try to report any price like 5.00 or 10.00 (whole dollar amounts) it just truncates the ending .00, which isnt exactly a problem but I would rather have it display the trailing zeros so everything looks nice and similar. Here is the code for the array/reporting loop:
$items = Array
(
"0"=> Array
(
"name" => $_SESSION['itemname-mo'],
"price" => $_SESSION ['price-mo'],
"sku" => $_SESSION ['sku-mo']
),
"1" => Array
(
"name" => $_SESSION['itemname-addon'],
"price" => $_SESSION ['price-addon'],
"sku" => $_SESSION ['sku-addon']
),
"2" => Array
(
"name" => $_SESSION['itemname-addon1'],
"price" => $_SESSION ['price-addon1'],
"sku" => $_SESSION ['sku-addon1']
),
"3" => Array
(
"name" => $_SESSION['itemname-addon2'],
"price" => $_SESSION ['price-addon2'],
"sku" => $_SESSION ['sku-addon2']
)
);
$a_length = count($items);
for($x = 0; $x<$a_length; $x++){
$total +=$items[$x]['price'];
}
echo "<div class=\"well\">";
for($i = 0; $i < $a_length; $i++){
$name = $items[$i]['name'];
$price = $items[$i]['price'];
$sku = $items[$i]['sku'];
displaycart($name,$price,$sku);
}
echo "<br />
Sub Total:
$$total";
echo "</div>";
function displaycart($name,$price,$sku){
if($name != null || $price != null || $sku != null){
echo "$name: $$price ($sku) <br />";
}
else{ echo "";}
}
See number_format.
number_format($number, 2, '.', '');
Use number_format when echo'ing.
Related
This question already has an answer here:
get cheap price with min() from array
(1 answer)
Closed 7 months ago.
I have an array like this:
$flight = array (
array (
"home" => "AMS",
"away" => "LHR",
"price" => "270"
),
array (
"home" => "AMS",
"away" => "LGW",
"price" => "216"
),
array (
"home" => "EIN",
"away" => "LHR",
"price" => "427"
)
);
I want the values from the cheapest flight. The result should be: AMS LGW 216.
When I loop trough the array I can get the lowest price result but not the other values from the array home and away.
foreach ($flight as $value) {
echo $value["home"].' '.$value["away"].' '.$value["price"].'<br>';
$lowest = array_column($flight, "price");
$min = min($lowest);
}
echo $min;
The result now is only 216
But the result I want AMS LGW 216
How can I create this?
One option is to remember what the values were at the lowest price and just iterate over all of them:
$min = null;
foreach ($flight as $value) {
if ($min === null || $value['price'] < $min) {
$minValue = $value;
$min = $value['price'];
}
}
echo $minValue["home"].' '.$minValue["away"].' '.$minValue["price"];
Store the entire item not just the price.
$min = ["price" => 1e10];
foreach ($flight as $value) {
echo $value["home"] . ' ' . $value["away"] . ' ' . $value["price"] . '<br>';
if ($value['price'] < $min['price']) {
$min = $value;
}
}
print_r($min);
Sort the array by field (ASC order) and you'll find the lowest element in the head of your array:
usort($flights, fn($a, $b) => $a['price'] <=> $b['price'])
print_r($flights[0]);
You can use array_keys and with your code.
Here is the code:
$flight = array(
array(
"home" => "AMS",
"away" => "LHR",
"price" => "270"
),
array(
"home" => "AMS",
"away" => "LGW",
"price" => "216"
),
array(
"home" => "EIN",
"away" => "LHR",
"price" => "427"
)
);
$lowest = array_column($flight, "price");
$lowset_array = array_keys($lowest, min($lowest));
print_r($flight[reset($lowset_array)]);
//OR
//print_r($flight[$lowset_array[0]]);
And here is the output:
Array
(
[home] => AMS
[away] => LGW
[price] => 216
)
Before providing solutions: your implementation it's finding the lowest price several times (the number of flights). You can get the cheapest price with:
$lowest = array_column($flight, 'price');
echo min($lowest);
You may use two variables to save the lowest price and the associated flight:
function getCheapestFlight(array $flights): array
{
$cheapestFlight = null;
$lowest = PHP_INT_MAX;
foreach ($flights as $flight) {
$price = $flight['price'];
if ($price < $lowest) {
$lowest = $price;
$cheapestFlight = $flight;
}
}
return $cheapestFlight;
}
Or use only one variable for the cheapest flight:
function getCheapestFlight(array $flights): array
{
$cheapestFlight = reset($flights);
foreach ($flights as $flight) {
$price = $flight['price'];
if ($price < $cheapestFlight['price']) {
$cheapestFlight = $flight;
}
}
return $cheapestFlight;
}
If you prefer functional programming:
function getCheapestFlight(array $flights): array
{
return array_reduce(
$flights,
function ($cheapestFlight, $flight) {
return $flight['price'] < $cheapestFlight['price']
? $flight
: $cheapestFlight;
},
reset($flights)
);
}
I have a set of products. Based on the state of the page, I'm displaying one product and then up to 4 other products. The result set of the products can be any size greater than 5 products. I want to ALWAYS show 5 products. If available I want to show the 2 products below(in the result set) and the 2 products above.
Examples:
If there are 10 results and the key product is 5. I want to show 3,4,5,6,7.
If there are 10 results and the key product is 9. I want to show 6,7,8,9,10.
If there are 10 results and the key product is 1. I want to show 1,2,3,4,5.
Right now I'm using min() and max() and some "IF"s to figure it out and it takes a ridiculous number of lines of code, when there is an elegant solution out there, I'm just not finding it!
example array result set below
$similar_products = array(
array(
"id" => 1,
"title" => "Product One"
),
array(
"id" => 2,
"title" => "Product Two"
),
array(
"id" => 3,
"title" => "Product Three"
),
array(
"id" => 4,
"title" => "Product Four"
),
array(
"id" => 5,
"title" => "Product Five"
),
array(
"id" => 6,
"title" => "Product Six"
),
array(
"id" => 7,
"title" => "Product Seven"
),
array(
"id" => 8,
"title" => "Product Eight"
),
array(
"id" => 9,
"title" => "Product Nine"
),
array(
"id" => 10,
"title" => "Product Ten"
)
);
$i = 8; //change this value to test different key product array positions
$arrOut = array();
$floor = 0;
if($i <= 1) { //the key product is either in the first or second position in the array
$floor = 0;
$arrOut[] = $similar_products[0];
$arrOut[] = $similar_products[1];
$arrOut[] = $similar_products[2];
$arrOut[] = $similar_products[3];
$arrOut[] = $similar_products[4];
} elseif((count($similar_products)-1)-$i <= 1) { //the key product is either in the last or second to last in the array
$floor = count($similar_products)-5;
$arrOut[] = $similar_products[count($similar_products)-5];
$arrOut[] = $similar_products[count($similar_products)-4];
$arrOut[] = $similar_products[count($similar_products)-3];
$arrOut[] = $similar_products[count($similar_products)-2];
$arrOut[] = $similar_products[count($similar_products)-1];
} else { //otherwise, just grab two above and two below
$floor = $i-2;
$arrOut[] = $similar_products[$i-2];
$arrOut[] = $similar_products[$i-1];
$arrOut[] = $similar_products[$i];
$arrOut[] = $similar_products[$i+1];
$arrOut[] = $similar_products[$i+2];
}
$x = $floor; //set x, our counter, to the floor (floor = the very first output postion)
foreach($arrOut as $ao) {
if($x == $i) { //current key product
echo "<strong>" . $ao['id'] . ":" . $ao['title'] . "</strong><hr/>";
} else { //other NON key products
echo $ao['id'] . ":" . $ao['title'] . "<hr/>";
}
$x++;
}
If you want you can remove the variable config, condense it a bit, and make it a 1-liner ;-)
I'm not good with this stuff, so there are probably more efficient and/or shorter options.
// Set array index, starts with 0
// If you need to find with specific ID, just find the index by the ID
$primaryIndex = 4;// change this number to test
// How many extra items to show
// Must be divisible by 2
$extraToShow = 4;
// Find total items available - 1 to work with array indexes
$maxIndex = count($similar_products) - 1;
// Find the slice start
$low = min($maxIndex - $extraToShow, max(0, $primaryIndex - 1 - $extraToShow / 2));
// Slice to needed
$items = array_slice($similar_products, $low, $extraToShow + 1);
var_dump($items);
<?php
// example code
$productKey = 7;
$resultsShown = 5;
$totalResults = 10;//num_rows()?
$limit = floor($resultsShown/2);
$min = $limit;
$max = $totalResults - $limit;
if($productKey<=$min){
for($i = 1;$i<=$resultsShown; $i++){
//Display result
echo $i;
}
}
else if($productKey>$max){
for( $i = $totalResults - $resultsShown+1; $i <=$totalResults;$i++){
//Display result
echo $i;
}}
else{
for( $i = $productKey - $limit; $i<=$productKey + $limit; $i++){
//Display result
echo $i;
}
}
Haven't had chance to test as I'm on mobile, but the simplest way I could think to solve the problem while giving you chance to change those fixed limits in the future, not elegant, but can't see what you have at the moment to compare!
I'm writing a PHP script for available rooms in a hotel. I want every combination for a group (i.e. 4 person). This is my array.
$room_array = array(
array(
"title" => "1 person room",
"room_for" => 1,
"price" => 79
),
array(
"title" => "2 person room with other",
"room_for" => 1,
"price" => 69
),
array(
"title" => "2 person room alone",
"room_for" => 1,
"price" => 89
),
array(
"title" => "2 person",
"room_for" => 2,
"price" => 69
),
array(
"title" => "3 person",
"room_for" => 3,
"price" => 69
)
);
Possible outcome:
4x 1 person room
4x 2 person room with other
3x 1 person room + 1x 2 person room with other
2x 2 person room
1x 3 person room + 1x 1 person room
etc. etc.
This calls for a recursive function. But every example I looked at doesn't work with counting in the inner array. The closest i found was this question:
Finding potential combinations of numbers for a sum (given a number set to select from)
But i didn't get de solution to work..
UPDATE:
Hi, thanks for all the answers. Really helped me in finding the best practice. In the meantime, the assignment has changed a little so I can't answer my own original question. My problem is solved. Thanks again for the help!
My answer below will get you partway there.
Resources
I borrowed some code logic from this answer.
To quote the answer (in case of future removal), please view below.
You can try
echo "<pre>";
$sum = 12 ; //SUM
$array = array(6,1,3,11,2,5,12);
$list = array();
# Extract All Unique Conbinations
extractList($array, $list);
#Filter By SUM = $sum $list =
array_filter($list,function($var) use ($sum) { return(array_sum($var) == $sum);});
#Return Output
var_dump($list);
Output
array
0 => array
1 => string '1' (length=1)
2 => string '2' (length=1)
3 => string '3' (length=1)
4 => string '6' (length=1)
1 => array
1 => string '1' (length=1)
2 => string '5' (length=1)
3 => string '6' (length=1)
2 => array
1 => string '1' (length=1)
2 => string '11' (length=2)
3 => array
1 => string '12' (length=2)
Functions Used
function extractList($array, &$list, $temp = array()) {
if(count($temp) > 0 && ! in_array($temp, $list))
$list[] = $temp;
for($i = 0; $i < sizeof($array); $i ++) {
$copy = $array;
$elem = array_splice($copy, $i, 1);
if (sizeof($copy) > 0) {
$add = array_merge($temp, array($elem[0]));
sort($add);
extractList($copy, $list, $add);
} else {
$add = array_merge($temp, array($elem[0]));
sort($add);
if (! in_array($temp, $list)) {
$list[] = $add;
}
}
}
}
My answer
The code below uses the code referenced above. I changed the return functionality of the array_filter function to map it to your needs.
The only thing left for you to do is change the function so that it can catch multiple of the same type of room. At the moment, the code below will only output 1 of each type of room (as per the code referenced above). An easy way to get around this would be to multiply the array values you send to the function by the number of guests you are searching for rooms, but up to the amount of rooms available. So: if you are looking to book for 4 guests and you have no single rooms remaining and only 1 double room, your best match result would have to be a 2 person room and a 3 person room. I've added some brief functionality to add this (it's commented out), although I have not tested it. It will likely take a while to process that as well so if you're looking for a quicker method, you're gonna have to use a better algorithm as already mentioned in previous comments/answers or solve P vs NP
The code below also gives you the option to toggle a value of $exact. This value, if set to true, will return only matches exactly equal to the number of guests, and if set to false will return all matches that equal to at least the number of guests.
<?php
class Booking {
private $minGuests = 1;
protected $guests = 1;
protected $rooms = [];
public function getRoomCombinations(bool $exact = true) {
$guests = $this->guests;
$list = [];
$rooms = $this->rooms;
/*for($i = 0; $i < $guests-1; $i++) {
$rooms = array_merge($rooms, $this->rooms);
}
asort($rooms);*/
$this->extractList($rooms, $list);
$result = array_filter($list, function($var) use ($guests, $exact) {
if($exact)
return(array_sum(array_map(function($item) { return $item['room_for'];}, $var)) == $guests);
else
return(array_sum(array_map(function($item) { return $item['room_for'];}, $var)) >= $guests && count($var) <= $guests);
});
array_multisort(array_map('count', $result), SORT_ASC, $result);
return $result;
}
private function extractList(array $array, array &$list, array $temp = []) {
if (count($temp) > 0 && !in_array($temp, $list))
$list[] = $temp;
for($i = 0; $i < sizeof($array); $i++) {
$copy = $array;
$elem = array_splice($copy, $i, 1);
if (sizeof($copy) > 0) {
$add = array_merge($temp, array($elem[0]));
sort($add);
$this->extractList($copy, $list, $add);
} else {
$add = array_merge($temp, array($elem[0]));
sort($add);
if (!in_array($temp, $list)) {
$list[] = $add;
}
}
}
}
public function setGuests(int $guests) {
$this->guests = ($guests >= $this->minGuests ? $guests : $this->minGuests);
return $this;
}
public function setHotelRooms(array $rooms) {
$this->rooms = $rooms;
return $this;
}
}
$booking = (new Booking())
->setGuests(4)
->setHotelRooms([
[
"title" => "1 person room",
"room_for" => 1,
"price" => 79
],
[
"title" => "2 person room with other",
"room_for" => 1,
"price" => 69
],
[
"title" => "2 person room alone",
"room_for" => 1,
"price" => 89
],
[
"title" => "2 person",
"room_for" => 2,
"price" => 69
],
[
"title" => "3 person",
"room_for" => 3,
"price" => 69
]
]);
echo '<pre>' . var_export($booking->getRoomCombinations(true), true) . '</pre>';
?>
If you need all the combinations then you can use an backtracking iterative algorithm (depth path).
In summary:
Type of tree: binary tree because all the levels can contain a solution when the number of persons contabilized = objetive
Binary tree
Algorithm functions
You need to increment the cont every time that a level is generated with the number of persons of the level and decrement when you change your track (exploring brothers or back)
solution: array[0..levels-1] values {0 (node not selected) ,1 (node selected)}
solution[0] = 1 -> You choose that "1 person room" belongs to the solution
solutions: list/array of objects and every object contains array of titles of rooms
function Backtracking ()
level:= 1
solution:= s_initial
end:= false
repeat
generate(level, solution)
IF solution(level, solution) then
save_solution
else if test(level, solution) then
level:= level+ 1
else
while NOT MoreBrothers(level, solution)
go_back(level, s)
until level==0
2.1. Generate: generate next node
2.2. Solution: test if it's a solution
2.3. Critery: if we must continue by this track or bound
2.4. MoreBrothers: if there are nodes without check at this level
2.5. Backtrack: all the nodes at this level were explored
2.6. Save solution: add to the solutions array your object that contains strings
$room_array = array(
array(
"title" => "1 person room",
"room_for" => 1,
"price" => 79
),
array(
"title" => "2 person room with other",
"room_for" => 1,
"price" => 69
),
array(
"title" => "2 person room alone",
"room_for" => 1,
"price" => 89
),
array(
"title" => "2 person",
"room_for" => 2,
"price" => 69
),
array(
"title" => "3 person",
"room_for" => 3,
"price" => 69
)
);
// Gets rooms based on a given number of guests
function get_possible_rooms($num_guests) {
global $room_array;
$possible_rooms = [];
foreach ($room_array as $room) {
if ($num_guests <= $room['room_for']) {
$possible_rooms[] = $room['title'];
}
}
return $possible_rooms;
}
// Gets the available room capacities
function get_room_capacities() {
global $room_array;
$capacities = [];
foreach ($room_array as $room) {
$capacities[] = $room['room_for'];
}
return array_unique($capacities);
}
// Gets the different combinations of groups of guests based on the room capacities
function get_guest_assignments($remaining_guests, $parent_id = '', $num_guests, &$result) {
$room_capacities = get_room_capacities();
for ($i = 1; $i <= $remaining_guests; ++$i) {
if (in_array($i, $room_capacities)) {
$parent_guests = (isset($result[$parent_id])) ? $result[$parent_id] : 0;
$result[$parent_id . $i] = $parent_guests + $i;
for ($j = 1; $j <= $remaining_guests - $i; ++$j) {
// Recursively get the results for children
get_guest_assignments($j, $parent_id . $i, $num_guests, $result);
}
}
}
if ($remaining_guests === 1 && $parent_id !== '') {
// If it reaches the end and it does not fulfill the required number of guests,
// mark it for removal later
if ($result[$parent_id] < $num_guests) {
$result[$parent_id] = null;
}
}
// This is the last recursion
if ($result[$parent_id . '1'] === $num_guests) {
// Remove duplicates.
// To do this, we need to re-sort the keys (e.g. 21 becomes 12) and call array_unique()
// I admit this is a bit sloppy implementation.
$combinations = [];
foreach ($result as $key => $value) {
if ($value !== null) {
$nums = str_split($key);
sort($nums);
$combinations[] = implode('', $nums);
}
}
$result = array_unique($combinations);
}
}
// Gets the rooms for each group of guest
function get_room_assignments($guest_str) {
$rooms = [];
for ($i = 0; $i < strlen($guest_str); ++$i) {
$num_guests = intval(substr($guest_str, $i, 1));
$rooms[] = get_possible_rooms($num_guests);
}
return $rooms;
}
//----------
// RUN
//----------
$guests = 4;
$result = [];
get_guest_assignments($guests, null, $guests, $result);
foreach ($result as $guest_combi) {
$assignments = get_room_assignments($guest_combi);
// Printing output
echo 'Guest Combination ' . $guest_combi . "\n";
echo json_encode($assignments, JSON_PRETTY_PRINT);
echo "\n\n";
}
The output will look something like this:
...
Guest Combination 13
[
[
"1 person room",
"2 person room with other",
"2 person room alone",
"2 person",
"3 person"
],
[
"3 person"
]
]
...
"Guest combination 13" means the 4 guests will be split into groups of 1 and 3 persons.
Output is an array of possible rooms for each group. So in the example, the group of 1 can book 1 person room, 2 person room with other, ... 3 person room. And the group of 3 can book 3 person room.
—
Other notes:
I know we hate global but doing this just for brevity. Feel free to modify.
There's a shorter way to code this, but this implementation makes it easier to debug since guest combinations are used as keys.
I Am trying to compare 3 different array prices in order to find the lowest so that I can decide which array values should be input into a database, the code looks something like this at the moment...
$array_a = array(
"id" => 398,
"price" => 100
);
$array_b = array(
"id" => 387,
"price" => 60
);
$array_c = array(
"id" => 127,
"price" => 50
);
if($array_a && $array_b && $array_c){
$newArr = array($array_a['price'], $array_b['price'], $array_c['price']);
array_keys($newArr, min($newArr));
print_r($newArr)."\n";
}
The above code does not return the correct index of the array with the lowest price which in this case would be 2 (array_c), what would be the correct way to find out the key of the lowest value.
Also what would be the best way to make sure that only numbers are compared with the min() function as opposed to strings?
You can automate it for example in this manner:
$newArr = array($array_a['price'], $array_b['price'], $array_c['price']);
asort($newArr, SORT_NUMERIC);
echo "Minimum: ".reset($newArr).", given in array #".key($newArr);
I 'm not so sure how to answer your closing question -- what should happen if the values are not actually typed as numbers?
Update: Here's one way to exclude non-numeric values:
asort($newArr, SORT_NUMERIC);
while (!is_numeric(current($newArr))) next($newArr);
if (key($newArr) === null) {
echo "No valid elements found";
}
else {
echo "Minimum: ".current($newArr).", given in array #".key($newArr);
}
You can do:
$newArr = array($array_a['price'], $array_b['price'], $array_c['price']);
sort($newArr);
$lowest = array_shift($newArr);
Try this:
$keys = array_keys($your_array);
asort($keys);
$min = $keys[0];
echo "Smallest index: ".$min;
<?php
$array_a = array(
"id" => 398,
"price" => 100
);
$array_b = array(
"id" => 387,
"price" => 60
);
$array_c = array(
"id" => 127,
"price" => 50
);
if($array_a && $array_b && $array_c){
$newArr = array($array_a['price'], $array_b['price'], $array_c['price']);
$key_min = array_keys($newArr, min($newArr));
echo $key_min[0];
}
?>
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Search and replace inside an associative array
I think this may have been asked before. But I just want a simple solution.
I have an array like this:
Array ( "name" => "Krish",
"age" => "27",
"COD" => ""
)
I want to replace "" with "0"
Its a multidimentional array. The return value should be array too.
Edit: I tried preg_replace and str_replace. For some reason, these did not work for me.
$array = array(
"name" => "Krish",
"age" => "27",
"COD" => ""
);
you may loop the array and repalce what you want
foreach($array as $key => $value)
{
if($value == "") $array[$key] = 0;
}
Note:
if you know what key is it you can do it like this
$array['cod'] = 0;
$entry = array("name" => "Krish",
"age" => "27",
"COD" => "");
$arr = array_filter($entry, 'valcheck');
print_r($entry); //ORIGINAL ARRAY
print_r($arr); //MODIFIED ARRAY
function valcheck($var)
{
if($var === "")
return 0;
else
return $var;
}
if your array is $array:
$array['COD'] = "0";
<?php
$arr=array(
"name" => "Krish",
"age" => "27",
"COD" => ""
);
print_r(array_map(function($i){return (''===$i)?0:$i;},$arr));
?>