This is more of an algorithm problem than a PHP problem, but I can't seem to figure it out!
I've got a multi dimensional array as following :
[
210875 => ["2", "1"],
129096 => ["2", "2"]
]
There are 2 ids but there could be more. I want to keep in my table only 1 id depending on these conditions.
Pseudo code:
if a[0] == 1 and a[1] >= 1: # the id gets deleted right away without looking at other conditions
if a[0] >= 2 and a[1] == 2: # it stays if nothing below fits else it gets deleted
if a[0] >= 3 and a[1] == 3: # it stays if nothing below fits else it gets deleted
if a[0] >= 8 and a[1] == 4: # it stays if nothing below fits else it gets deleted
# ... etc
If two fit the same conditions then one of them randomly gets deleted.
For example (pseudo code):
a[0] == 2 and a[1] == 1
a[0] == 2 and a[1] == 2
I've tried doing the following, but I can't figure out how to dynamically have if-conditions made dependent on my algorithm :
$sub_array = array();
foreach($array as $k=>$v) {
if($v[0] == 1 && $v[1] == 1) continue;
if($v[0] >= 2 && $v[1] == 2) $sub_array[$k] = $v;
if($v[0] >= 6 && $v[1] == 3) $sub_array[$k] = $v;
if($v[0] >= 8 && $v[1] == 4) $sub_array[$k] = $v;
// etc ...
}
Also, when I do that, how to know which one is the highest in my sub array?
It is not entirely clear to me what your conditions are, but to me it looks like you really are giving a rank to each of your rows, where in the end you want to keep the row with the highest rank.
Even if my interpretation of your rules might not be exactly what you intended, you can tune it by adapting the scores in the code below. I would also suggest to swap the conditions so that the == comparison comes first. That will be a bit more efficient:
$keepKey = null;
$bestScore = -1;
foreach($array as $k=>$v) {
$score = 0;
if ($v[1] == 1 && $v[0] == 1) $score = 1;
if ($v[1] == 2 && $v[0] >= 2) $score = 2;
if ($v[1] == 3 && $v[0] >= 6) $score = 3;
if ($v[1] == 4 && $v[0] >= 8) $score = 4;
// ... etc ...
if ($score > $bestScore) {
$keepKey = $k;
$bestScore = $score;
}
}
$sub_array = [$keepKey => $array[$keepKey]]; // Only keep the entry with highest score
If it is important to really pick a random one in case of ties, then shuffle the keys before starting the loop:
$keepKey = null;
$bestScore = -1;
$keys = array_keys($array); // <---
shuffle($keys); // <
foreach($keys as $k) { // <
$v = $array[$k]; // <---
$score = 0;
if ($v[1] == 1 && $v[0] == 1) $score = 1;
if ($v[1] == 2 && $v[0] >= 2) $score = 2;
if ($v[1] == 3 && $v[0] >= 6) $score = 3;
if ($v[1] == 4 && $v[0] >= 8) $score = 4;
echo $score . "\n";
if ($score > $bestScore) {
$keepKey = $k;
$bestScore = $score;
}
}
$sub_array = [$keepKey => $array[$keepKey]];
Related
I'm trying to create a bingo game that generates 120 tickets. Each Ticket is a [3x9 matrix] and contains numbers between 1-90. Rules for generating tickets are:
RULE #1 - Each row cannot have more than 5 numbers.
RULE #2 - Each column is assigned a range of numbers: (ex. 1-9 can appear only in column 1, 10-19 can appear only in column 2 and so on. And in column 9 numbers between 80-90 can appear)
RULE #3 - In a specific column, numbers must be arranged in ascending order from top to bottom.
RULE #4 - Each column must have at least one number in it.
RULE #5 - All the numbers 1 to 90 are used only once in each set of 6 tickets.
I'm able to fulfill all rules except RULE #5. Here's my code that I've written so far.
$batch_numbers = array(); //to keep track of numbers used in the set of 6 ticekts
$reset = false; // to check if the set is complete
$ticket_set = 1; // set count
for ($t=1; $t <= 120; $t++) {
$ticket_array = array(array(0,0,0,0,0,0,0,0,0), array(0,0,0,0,0,0,0,0,0), array(0,0,0,0,0,0,0,0,0));
$numbers = range(1, 90);
$indices = array();
$random_indices = array();
$used_numbers = array(); // to check unique numbers in a ticket
$full_ticket = array();
for($i=0;$i<3;$i++){
for($j=0;$j<9;$j++){
$indice = array($i, $j);
array_push($indices, $indice);
}
}
#if reset is true (means a set of 6 is complete) so set the batch_numbers array to empty and increment the ticket_set value
if($reset){
$batch_numbers = array();
$reset = false;
$ticket_set++;
}
#if ticket number is divisible by 6 set the reset variable to true to indicate the end of a set of 6 tickets
if(($t%6)==0){
$reset = true;
}
#selecting 5 random positions to fill the first row
$first_row_numbers = range(0,8);
shuffle($first_row_numbers);
$keys_one = array_rand($first_row_numbers, 5);
$first_row = array();
foreach ($keys_one as $row_one_key) {
array_push($first_row, $indices[$row_one_key]);
}
#selecting 5 random positions to fill the second row
$second_row_numbers = range(9,17);
shuffle($second_row_numbers);
$keys_two = array_rand($second_row_numbers, 5);
$second_row = array();
foreach ($keys_two as $row_two_key) {
array_push($second_row, $indices[$second_row_numbers[$row_two_key]]);
}
#selecting 5 random positions to fill the third row
$third_row_numbers = range(18,26);
shuffle($third_row_numbers);
$keys_three = array_rand($third_row_numbers, 5);
$third_row = array();
foreach ($keys_three as $row_three_key) {
array_push($third_row, $indices[$third_row_numbers[$row_three_key]]);
}
#push the selected 5 positions of first row to random_indices array that satisfies RULE #1
foreach($first_row as $row_one){
array_push($random_indices, $row_one);
}
#push the selected 5 positions of second row to random_indices array that satisfies RULE #1
foreach($second_row as $row_two){
array_push($random_indices, $row_two);
}
#push the selected 5 positions of third row to random_indices array that satisfies RULE #1
foreach($third_row as $row_three){
array_push($random_indices, $row_three);
}
#assign the numbers between 1-90 according to its column position to satisfy RULE #2
foreach($random_indices as $indice){
list($row, $column) = $indice;
#generate a unique number for the current set of 6 tickets
$rand = $this->generateRandomColumnNumber($column, $batch_numbers);
#assign the number to the array
$ticket_array[$row][$column] = $rand;
#push the unique number to batch_numbers array so that we can keep track of the numbers used in set of 6 tickets that satisfies RULE #5
array_push($batch_numbers, $rand);
#Push the unique number to used_numbers array so that we can keep track of the numbers already used in the individual ticket
array_push($used_numbers, $rand);
}
#Sort the ticket_array column wise to satisfy the RULE #3
for($k=0; $k<9; $k++){
# if all the rows are filled with random number
if($ticket_array[0][$k] != 0 && $ticket_array[1][$k] != 0 && $ticket_array[2][$k] != 0){
$temp_1 = NULL;
$temp_2 = NULL;
if($ticket_array[0][$k] > $ticket_array[1][$k]){
$temp_1 = $ticket_array[0][$k];
$ticket_array[0][$k] = $ticket_array[1][$k];
$ticket_array[1][$k] = $temp_1;
}
if($ticket_array[1][$k] > $ticket_array[2][$k]){
$temp_2 = $ticket_array[1][$k];
$ticket_array[1][$k] = $ticket_array[2][$k];
$ticket_array[2][$k] = $temp_2;
}
}
# if 1st and 2nd row are filled by random number
elseif($ticket_array[0][$k] != 0 && $ticket_array[1][$k] != 0 && $ticket_array[2][$k] == 0){
if($ticket_array[0][$k] > $ticket_array[1][$k]){
$temp = $ticket_array[0][$k];
$ticket_array[0][$k] = $ticket_array[1][$k];
$ticket_array[1][$k] = $temp;
}
}
# if 1st and 3rd row are filled by random number
elseif($ticket_array[0][$k] != 0 && $ticket_array[1][$k] == 0 && $ticket_array[2][$k] != 0){
if($ticket_array[0][$k] > $ticket_array[2][$k]){
$temp = $ticket_array[0][$k];
$ticket_array[0][$k] = $ticket_array[2][$k];
$ticket_array[2][$k] = $temp;
}
}
# if 2nd and 3rd rows are filled with random numbers
elseif($ticket_array[0][$k] == 0 && $ticket_array[1][$k] != 0 && $ticket_array[2][$k] != 0){
if($ticket_array[1][$k] > $ticket_array[2][$k]){
$temp = $ticket_array[1][$k];
$ticket_array[1][$k] = $ticket_array[2][$k];
$ticket_array[2][$k] = $temp;
}
}
# if 1st, 2nd and 3rd rows are empty we need to assign a value to the column so that it satisfies RULE #4
elseif($ticket_array[0][$k] == 0 && $ticket_array[1][$k] == 0 && $ticket_array[2][$k] == 0){
$modified_array = $this->fillEmptyColumn($k, $ticket_array, $batch_numbers, $batch, $game_id);
$ticket_array = $modified_array;
}
}
/* Code to store the ticket data in database */
}
protected function fillEmptyColumn($column, $ticket_array, $batch_numbers){
for ($i=0; $i < 9; $i++) {
if($i == $column){
continue;
}else{
//Check if all three rows have digits
if($ticket_array[0][$i] != 0 && $ticket_array[1][$i] != 0 && $ticket_array[2][$i] != 0){
$new_number = $this->generateRandomColumnNumber($column, $batch_numbers);
$ticket_array[2][$i] = 0;
$ticket_array[2][$column] = $new_number;
break;
}
//Check if 1st and 2nd rows have digits
elseif($ticket_array[0][$i] != 0 && $ticket_array[1][$i] != 0 && $ticket_array[2][$i] == 0){
$new_number = $this->generateRandomColumnNumber($column, $batch_numbers);
$ticket_array[1][$i] = 0;
$ticket_array[1][$column] = $new_number;
break;
}
//Check if 1st and 3rd rows have digits
elseif($ticket_array[0][$i] != 0 && $ticket_array[1][$i] == 0 && $ticket_array[2][$i] != 0){
$new_number = $this->generateRandomColumnNumber($column, $batch_numbers);
$ticket_array[2][$i] = 0;
$ticket_array[2][$column] = $new_number;
break;
}
//Check if 2nd and 3rd rows have digits
elseif($ticket_array[0][$i] == 0 && $ticket_array[1][$i] != 0 && $ticket_array[2][$i] != 0){
$new_number = $this->generateRandomColumnNumber($column, $batch_numbers);
$ticket_array[2][$i] = 0;
$ticket_array[2][$column] = $new_number;
break;
}
}
}
return $ticket_array;
}
protected function generateRandomColumnNumber($column, $batch_numbers)
{
#assign the numbers according to the column
if($column == 0){
$rand = rand(1, 9);
}elseif($column == 8){
$rand = rand(80,90);
}
else{
$rand = rand(($column *10), ((($column+1)*10)-1));
}
# check if numbers already exists in the current set of 6 tickets
if(in_array($rand, $batch_numbers)){
return $this->generateRandomColumnNumber($column, $batch_numbers);
}
return $rand;
}
Every time I try to call the generateRandomColumnNumber to generate a unique number and pass the batch_numbers array (to check unique number in the set of 6 tickets) instead of used_numbers array ( to check unique number in a individual ticket ) I get 500 error instantly but doesn't show why it is caused. Could anyone please help me out to point out what's wrong in my code and help me solve this. Been stuck at this for a couple of days now. It'd be of great help. Thanks
I have three integers: A, B, C
I want to print all integers from 1 to range which are divisible by A or B but not by C.
My code
for($n=0; $n < $range; $n++){
if(($n < $a && $n < $b) || ($n % $c == 0)){
return [];
}
if(($n % $a == 0 || $n % $b == 0) && ($n % $c > 0)){
$outputArr[] = $n;
}
}
Is there any more efficient way to do this?
You can speed this up but it is more complicated, especially if you must print these out in order. Here is a method that doesn't print them out in order.
First write a greatest common divisor (gcd) function in PHP, and then write a least common multiple (lcm) function that uses the gcd function. Compute m = lcm(a, b). Iterate over multiples of a and print them out if they are not divisible by c. Next, iterate over multiples of b and print them out if they are not divisible by m or c.
Other optimizations along these lines are possible. For example, you can precompute the multiples of a or b that are not multiples of m and store them in an array. This works if m is not too large, division is more expensive than array access in PHP, and range is significantly larger than m.
PHP version 7 or higher is so fast when only integer operations are used that micro-optimizations are no longer needed.
$res = [];
$a = 9;
$b = 13;
$c = 26;
$range = 10000;
for($n=$a; $n <= $range; $n += $a){
if($n%$c != 0) $res[] = $n;
}
for($n=$b; $n <= $range; $n += $b){
if($n%$c != 0) $res[] = $n;
}
$res = array_unique($res);
sort($res);
This example takes about 1 millisecond to calculate the 1411 values on my 8-year-old system. This time for the presentation of the result is several times greater.
I would use range() and array_filter().
$range = 20;
$A = 2;
$B = 3;
$C = 9;
$nums = array_filter(range(1, $range), function ($x) use ($A, $B, $C) {
return (!($x % $A) || !($x % $B)) && $x % $C;
});
var_dump($nums);
Here is a more optimized solution, that also works efficient when a and b are large. You can simply run through the multiples of a and b:
for($na=$a, $nb=$b; $na <= $range || $nb <= $range; ){
if ($na <= $nb) {
if ($na % $c != 0)
$outputArr[] = $na;
if ($na == $nb)
$nb += $b;
$na += $a;
} else {
if ($nb % $c != 0)
$outputArr[] = $nb;
$nb += $b;
}
}
Each output number is only generated once, and already in the desired order.
If you are afraid the modulo test is slow, you could also have a next multiple of c running along, but that looks like too much overhead.
I trying to print simple numbers from 1 to 10 using a for loop like this:
for($i = 0; $i <= 10; $i++){
if($i != 4 || $i != 6){
echo $i."<br/>";
}
}
Output:
0
1
2
3
4
5
6
7
8
9
10
I just want the output from 0 to 10 but the output should not contain the numbers 4 and 6.
It is working fine if I use the && operator but does not work if I use||.
I do not understand why this is not working - I think it should work with ||.
You don't want to print either 4 or 6, so you should be using &&.
The statement if($i != 4 || $i != 6) will trigger whenever $i is not equal to 4, or whenever $i is not equal to 6. Considering 4 is not equal to 6, it will trigger in both cases. It will reach $i = 4, and realise that $i is not equal to 6. This will step into the condition, as you say it only has to hold true for one or the other.
The statement if($i != 4 && $i != 6) implies that $i is not equal to 4 and $i is not equal to 6. Both conditions must hold true at the same time. When $i = 4, $i != 6 will be true, but $i != 4 will be false. Both conditions need to be true, so it will fail. Essentially, this could be rewritten as:
for($i = 0; $i <= 10; $i++){
if($i != 4) {
if($i != 6) {
echo $i."<br/>";
}
}
}
To skip over the numbers 4 and 6 in the loop, you have to use the and condition:
for($i = 0; $i <= 10; $i++){
if($i != 4 && $i != 6){
echo $i."<br/>";
}
}
Hope this helps!
You want &&. It would not work with ||; that means something different.
"x && y" means "only true if x is true and y is also true; otherwise false."
"x || y" means "true if either x is true or y is true; only false if both are false."
The contrapositive (i.e., "opposite") of ($i != 4 && $i != 6) is ($i == 4 || $i == 6).
Mixing in the || without swapping the comparisons as well means, in your case, "true if $i is not 4, or also true if $i is not 6." Since one of those cases must always true, the result is also always true.
<?php for ($i=0; $i < 10 ; $i++) {
if ($i != 4 && $i !=6){
echo $i."<br>";}}
?>
I have managed to create an algorithm to check the rank of a poker hand. It works 100% correctly, but it's very slow. I've been analysing the code, and the check straight function is one of the slowest parts of it.
So my question is, is there a better way of calculating whether a hand make a straight?
Here is some details:
7 cards, 2 from holder, 5 from board. A can be high or low.
Each card is assigned a value:
2 = 2
3 = 3
..
9 = 9
T = 10
J = 11
Q = 12
K = 13
A = 14
The script has an array of all 7 cards:
$cards = array(12,5,6,7,4,11,3);
So now I need to be able to sort this into an array where it:
discards duplicates
orders the card from lowest to highest
only returns 5 consecutive cards I.e. (3,4,5,6,7)
It needs to be fast; loops and iterations are very costly. This is what I currently use and when it tries to analyse say 15000 hands, it takes its toll on the script.
For the above, I used:
discard duplicates (use array_unique)
order cards from lowest to highest (use sort())
only return 5 consecutive cards (use a for loop to check the values of cards)
Does anyone have any examples of how I could improve on this? Maybe even in another language that I could perhaps look at and see how it's done?
Instead of working with array deduping and sorting, consider using a bitmask instead, and setting bits to 1 where the card value is set. A bitmask works like a Set datastructure and comes with additional advantages when it comes to detecting contiguous elements.
for ($i = 0; $i < count($cards); $i++) {
$card = $cards[$i];
// For each card value, set the bit
if ($card == 14) {
// If card is an ace, also set bit 1 for wheel
$cardBitmask |= 0x2;
}
$cardBitmask |= (1 << $card);
}
// To compare, you simply write a for loop checking for 5 consecutive bits
for($i = 10; $i > 0; $i--)
{
if ($cardBitmask & (0x1F << $i) == (0x1F << $i)) {
// Straight $i high was found!
}
}
Consider the Java implementation at this link. I've included it here:
public static boolean isStraight( Card[] h )
{
int i, testRank;
if ( h.length != 5 )
return(false);
sortByRank(h); // Sort the poker hand by the rank of each card
/* ===========================
Check if hand has an Ace
=========================== */
if ( h[4].rank() == 14 )
{
/* =================================
Check straight using an Ace
================================= */
boolean a = h[0].rank() == 2 && h[1].rank() == 3 &&
h[2].rank() == 4 && h[3].rank() == 5 ;
boolean b = h[0].rank() == 10 && h[1].rank() == 11 &&
h[2].rank() == 12 && h[3].rank() == 13 ;
return ( a || b );
}
else
{
/* ===========================================
General case: check for increasing values
=========================================== */
testRank = h[0].rank() + 1;
for ( i = 1; i < 5; i++ )
{
if ( h[i].rank() != testRank )
return(false); // Straight failed...
testRank++; // Next card in hand
}
return(true); // Straight found !
}
}
A quick Google search for "check for poker straight (desired_lang)" will give you other implementations.
You could just sort the cards and loop over them in an array - saving always the last card and compare them with the current one.
$cards = array(12,5,6,7,4,11,3);
sort($cards);
$last = 0;
$count = 0;
$wheel = false;
foreach ($cards as $card) {
if ($card == $last) {
continue;
} else if ($card == ++$last) {
$count++;
} else {
if ($last == 6) $wheel = true;
$count = 1;
$last = $card;
}
if ($count == 5 || ($card == 14 && $wheel)) {
echo "straight $last";
$straight = range($last - 4, $last);
break;
}
}
You may go like this, you don't need to sort or anything (assuming that 2 is 2 and 14 is ace):
$cards = [12,5,6,7,4,11,3];
function _inc(&$i) {
if ($i == 14)
$i = 2;
else
$i++;
return $i;
}
$straight = false;
for($i = 2; $i <= 14; $i++) {
$ind = $i;
if (!in_array($ind, $cards)) continue;
$s = [$ind, _inc($ind), _inc($ind), _inc($ind), _inc($ind)];
$straight = count(array_intersect($s, $cards)) == count($s);
if ($straight) break;
}
print $straight;
Edit 3:
As requested, I'm trying to simplify my question.
Here is a sample of some of my data from a xml file:
<entry>
<title>Entry 1</title>
<f:max_value_a>499 999</f:max_value_a>
<f:max_value_b>999 999</f:max_value_b>
<f:min_value_a>0</f:min_value_a>
<f:min_value_b>500 000</f:min_value_b>
<f:min_value_c>1 000 000</f:min_value_c>
<f:value_for_a>5,10</f:value_for_a>
<f:value_for_b>4,50</f:value_for_b>
<f:value_for_c>3,90</f:value_for_c>
</entry>
<entry>
<title>Entry 2</title>
<f:min_value_a>0</f:min_value_a>
<f:value_for_a>4,20</f:value_for_a>
</entry>
<entry>
<title>Entry 3</title>
<f:max_value_a>1 999 999</f:max_value_a>
<f:min_value_a>100 000</f:min_value_a>
<f:min_value_b>2 000 000</f:min_value_b>
<f:value_for_a>3,735</f:value_for_a>
<f:value_for_b>3,445</f:value_for_b>
</entry>
f:value_for_d is the highest value, and f:value_for_c is lower than d, and so on.
I have a dynamic targetvalue (lets just go with 2 000 000 in this example)
I want to get the value where max_value is greater than the targetvalue, but sometimes max_value is not defined and then set to "0". "0" in max_value should mean unlimited "roof". The min_value can not be greater than targetvalue, but sometimes min_value is not defined and then set to "0". "0" min_value should mean a unlimited "floor".
I have tried with this code
if ($value_for_d > 0 ){
if (($min_value_d <= $targetvalue) xor ($min_value_d == 0)){
if (($max_value_d >= $targetvalue) xor ($max_value_d == 0)){
$query_result = TRUE;
$value = $value_for_d;
}
}
}elseif ($value_for_c > 0 ){
if (($min_value_c <= $targetvalue) xor ($min_value_c == 0)){
if (($max_value_c >= $targetvalue) xor ($max_value_c == 0)){
$query_result = TRUE;
$value = $value_for_c;
}
}
}elseif ($value_for_b > 0 ){
if (($min_value_b <= $targetvalue) xor ($min_value_b == 0)){
if (($max_value_b >= $targetvalue) xor ($max_value_b == 0)){
$query_result = TRUE;
$value = $value_for_b;
}
}
}elseif ($value_for_a > 0 ){
if (($min_value_a <= $targetvalue) xor ($min_value_a == 0)){
if (($max_value_a >= $targetvalue) xor ($max_value_a == 0)){
$query_result = TRUE;
$value = $value_for_a;
}
}
}
If I run this code with a targetvalue of "2 000 000", I get this result:
Entry 1 - 3.9 (correct value is 3.9)
Entry 2 - 0 (correct value is 4.2)
Entry 3 - 3.445 (correct value is 3.445)
If I set the targetvalue to even lower, to 500 000, I get 0 on all my entries.
Edit 4:
If I do:
var_dump($min_value_d,$max_value_d,$min_value_c,$max_value_c,$min_value_b,$max_value_b,$min_value_a,$max_value_a);
I get this output: https://dpaste.de/DtjhO/
If the regions are always exclusive and always in the right order, I'd suggest you do something like this:
<?php
if($min_value_d <= $targetvalue) {
$value = $value_for_d;
} else if($min_value_c <= $targetvalue) {
$value = $value_for_c;
} else if($min_value_b <= $targetvalue) {
$value = $value_for_b;
} else if($min_value_b <= $targetvalue) {
$value = $value_for_b;
}
?>
However, if they are not always exclusive, you should be returning some form of array, as it may fulfil multiple criteria:
Assuming that $min_value_x is not set when it is not in the XML (As in, no minimum) and $max_value_x is not set when it is not in the XML (As in, no maximum)
<?php
$values = array();
//if (there is no minimum or its smaller than target) and (there is no maximum or its larger than target) and at least one of them is non-null
if((is_null($min_value_d) || preg_replace('/([^0-9.])/i', '',$min_value_d) <= $targetvalue) && (is_null($max_value_d) || preg_replace('/([^0-9.])/i', '',$max_value_d) >= $targetvalue) && !(is_null($min_value_d) && is_null($max_value_d))) $values[] = $value_for_d;
if((is_null($min_value_c) || preg_replace('/([^0-9.])/i', '',$min_value_c) <= $targetvalue) && (is_null($max_value_c) || preg_replace('/([^0-9.])/i', '',$max_value_c) >= $targetvalue) && !(is_null($min_value_c) && is_null($max_value_c))) $values[] = $value_for_c;
if((is_null($min_value_b) || preg_replace('/([^0-9.])/i', '',$min_value_b) <= $targetvalue) && (is_null($max_value_b) || preg_replace('/([^0-9.])/i', '',$max_value_b) >= $targetvalue) && !(is_null($min_value_b) && is_null($max_value_b))) $values[] = $value_for_b;
if((is_null($min_value_a) || preg_replace('/([^0-9.])/i', '',$min_value_a) <= $targetvalue) && (is_null($max_value_a) || preg_replace('/([^0-9.])/i', '',$max_value_a) >= $targetvalue) && !(is_null($min_value_a) && is_null($max_value_a))) $values[] = $value_for_a;
?>
As it turns out, your items are formatted with spaces, thus when converted to a float for interpretation it only looked at the first set of numbers. preg_replace('/([^0-9.])/i', '', $var) removes anything non-numerical. (This is quite computationally expensive, mind)