ChenXiu Posted January 12, 2023 Share Posted January 12, 2023 $data is an array of customers. This array shows the Customer's name, the item price, and the postage cost. The total cost will be "item price + postage cost." How do I sort this array based on the total cost? (the sum of postage and item) print_r($data); // prints this in my browser: Array ( [listings] => Array ( [0] => Array ( [item_price] => Array ( [value] => 60.00 ) [postage] => Array ( [price] => Array ( [value] => 20.00 ) ) [customer] => Array ( [name] => Barbara ) ) [1] => Array ( [item_price] => Array ( [value] => 40.00 ) [postage] => Array ( [price] => Array ( [value] => 30.00 ) ) [customer] => Array ( [name] => Fred ) ) [2] => Array ( [item_price] => Array ( [value] => 70.00 ) [postage] => Array ( [price] => Array ( [value] => 20.00 ) ) [customer] => Array ( [name] => Julie ) ) ) ) The result should be from lowest total to highest total. I tried this, but only got errors: $price = array_column($data["listings"]["item_price"] + $data["listings"]["postage"]); array_multisort( $price , SORT_ASC , $data["listings"] ); Am I going about this correctly? Thank you. Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/ Share on other sites More sharing options...
gw1500se Posted January 12, 2023 Share Posted January 12, 2023 Use usort. Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604563 Share on other sites More sharing options...
ChenXiu Posted January 12, 2023 Author Share Posted January 12, 2023 Thank you, but I still can't make it work with my specific array. To get to the item price, and delivery price, I need to loop through the array, and I cannot seem to do this without errors. To demonstrate that I am really trying...... I believe this gets me to the relevant part: foreach($data["listings"] as $each) { ....and once I'm there, then I have $each["item_price"]["value"] and $each["postage"]["price"]["value"] And therefore, the total item cost will be: $total_price = $each["item_price"]["value"] + $each["postage"]["price"]["value"]; After that, I have no clue..... I am forcing myself to learn Arrays, but there comes a point where I must ask for help when I get totally stumped. Thank you. Â Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604577 Share on other sites More sharing options...
Barand Posted January 13, 2023 Share Posted January 13, 2023 You were advised to use usort(). Your custom function would compare the totals of each pair of records ($a and $b) and return a negative value if $a should sort before $b or positive if $a sorts after $b. (ie total A - total B) $listings = $data['listings']; usort($listings, function($a, $b) { return $a['item_price']['value'] + $a['postage']['price']['value'] - $b['item_price']['value'] - $b['postage']['price']['value']; }); echo '<pre>' . print_r($listings, 1) . '</pre>'; Â 1 Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604578 Share on other sites More sharing options...
ChenXiu Posted January 13, 2023 Author Share Posted January 13, 2023 @Barand, that works! Thank you! Yes, I was advised to use usort() ....BUT I quickly found that usort (like sort, array_multisort, et al) requires the programmer have a basic understanding of arrays (e.g. array keys, key/value pairs, etc.), and this is the hardest concept for me to wrap my brain around. My experience of seeing array code such as yours is akin to shock and awe a non-technologically advanced tribal villager experiences when they see a satellite..... or a cellphone for the first time. Or when the UFO crashed at Roswell and army personnel were presented with anti-gravity technology......... "How the h*** do they know this stuff?" I've started from the basics, "Arrays 101," but the teaching examples are dumbed down, e.g. $array = array('a' , 'b' , 'c'); "This is how you can magically count how many elements are in $array: use 'array_count'" Wow, how useful. Not. And then if I go onto google / Stack Overflow and type keywords like "sort array based on sum" (like I did 1000 times already), there are these convoluted questions from people with ridiculous arrays (usually of sports teams and their stats, etc., or some professor trying to keep track of their students in Excel, etc.), and NO WAY to extrapolate clues from the "voted best answer" to apply to my own array question. Like the dog who really doesn't understand the relationship between the owner, the can opener sound, and the bowl of food that appears moments later, I really have no clue how you knew to start with "$listings = $data['listings']," but I'm happy it's now sitting in front of me. 😀  Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604590 Share on other sites More sharing options...
Barand Posted January 13, 2023 Share Posted January 13, 2023 40 minutes ago, ChenXiu said: I really have no clue how you knew to start with "$listings = $data['listings']," Because that is the array you want to sort? It wasn't really necessary as usort($data['listings'] would have done the same thing. But I felt your array had a surfeit of levels. Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604593 Share on other sites More sharing options...
ChenXiu Posted January 14, 2023 Author Share Posted January 14, 2023 I'm gonno 12 hours ago, Barand said: But I felt your array had a surfeit of levels. I'm gonna use that word in a sentence every day for the next week! 😀 Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604651 Share on other sites More sharing options...
ChenXiu Posted January 14, 2023 Author Share Posted January 14, 2023 Interesting: It appears that usort may not sort as anticipated when using decimal numbers (e.g. a dollar amount of $18.53 in my "item price + postage cost" example above). Multiplying by 100 seems to fix it. return (100 * $a['item_price']['value']) + (100 * $a['postage']['price']['value']) - (100 * $b['item_price']['value']) - (100 * $b['postage']['price']['value']); Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604664 Share on other sites More sharing options...
Barand Posted January 14, 2023 Share Posted January 14, 2023 Works for me with decimal values. <?php $data = [ [ 'price' => 8.50, 'postage' => 3.50 ], [ 'price' => 2.50, 'postage' => 1.50 ], [ 'price' => 7.50, 'postage' => 2.10 ], [ 'price' => 10.00, 'postage' => 1.50 ], [ 'price' => 2.50, 'postage' => 1.80 ] ]; usort($data, function($a, $b) { return $a['price'] + $a['postage'] - $b['price'] - $b['postage']; }); echo '<pre>' . print_r($data, 1) . '</pre>'; ?> results Array ( [0] => Array ( [price] => 2.5 [postage] => 1.5 ) [1] => Array ( [price] => 2.5 [postage] => 1.8 ) [2] => Array ( [price] => 7.5 [postage] => 2.1 ) [3] => Array ( [price] => 8.5 [postage] => 3.5 ) [4] => Array ( [price] => 10 [postage] => 1.5 ) ) Â Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604667 Share on other sites More sharing options...
Barand Posted January 15, 2023 Share Posted January 15, 2023 19 hours ago, ChenXiu said: e.g. a dollar amount of $18.53 Do your prices contain the '$'? Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604692 Share on other sites More sharing options...
ChenXiu Posted January 15, 2023 Author Share Posted January 15, 2023 When there is zero, the result is incorrect: <?php $data = [ [ 'price' => 8.50, 'postage' => 3.50 ], [ 'price' => 6.18, 'postage' => 2.33 ], [ 'price' => 6.13, 'postage' => 0 ], [ 'price' => 4.19, 'postage' => 2.63 ], [ 'price' => 2.50, 'postage' => 1.80 ] ]; usort($data, function($a, $b) { return $a['price'] + $a['postage'] - $b['price'] - $b['postage']; }); echo '<pre>' . print_r($data, 1) . '</pre>'; ?> Â Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604695 Share on other sites More sharing options...
ChenXiu Posted January 15, 2023 Author Share Posted January 15, 2023 (edited) Dogs and cats fix the error: <?php $data = [ [ 'price' => 8.50, 'postage' => 3.50 ], [ 'price' => 6.49, 'postage' => 0 ], [ 'price' => 6.10, 'postage' => 0 ], [ 'price' => 10.00, 'postage' => 1.50 ], [ 'price' => 2.50, 'postage' => 1.80 ] ]; usort($data, function($a, $b) { $dog = $a['price'] + $a['postage']; $cat = $b['price'] + $b['postage']; return $dog - $cat; }); echo '<pre>' . print_r($data, 1) . '</pre>'; ?> Â Edited January 15, 2023 by ChenXiu Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604696 Share on other sites More sharing options...
Barand Posted January 15, 2023 Share Posted January 15, 2023 Your array (with the 0) sorted correctly for me without bringing in the menagerie ??? Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604697 Share on other sites More sharing options...
ChenXiu Posted January 16, 2023 Author Share Posted January 16, 2023 (edited) This specific array causes the problem: <?php $data = [ [ 'price' => 8.50, 'postage' => 3.50 ], [ 'price' => 6.18, 'postage' => 2.33 ], [ 'price' => 6.13, 'postage' => 0 ], [ 'price' => 4.19, 'postage' => 2.63 ], [ 'price' => 2.50, 'postage' => 1.80 ] ]; usort($data, function($a, $b) { return $a['price'] + $a['postage'] - $b['price'] - $b['postage']; }); echo '<pre>' . print_r($data, 1) . '</pre>'; // $data[1] and $data[2] are in wrong position ?> $data[1] and $data[2] are not in the correct position. But if I do something like the following code, then the result is correct: <?php $data = [ [ 'price' => 8.50, 'postage' => 3.50 ], [ 'price' => 6.18, 'postage' => 2.33 ], [ 'price' => 6.13, 'postage' => 0 ], [ 'price' => 4.19, 'postage' => 2.63 ], [ 'price' => 2.50, 'postage' => 1.80 ] ]; usort($data, function($a, $b) { $cat = $a['price'] + $a['postage']; $dog = $b['price'] + $b['postage']; if($cat > $dog) { $result = 1; } elseif ($cat < $dog) { $result = -1; } return $result; }); echo '<pre>' . print_r($data, 1) . '</pre>'; // The result order is now correct. ?> Â Edited January 16, 2023 by ChenXiu Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604722 Share on other sites More sharing options...
Barand Posted January 16, 2023 Share Posted January 16, 2023 I modified the code slightly tot add a 'total' element to each of the arrays to make sequence order easier to check. Revised code <?php $data = [ [ 'price' => 8.50, 'postage' => 3.50 ], [ 'price' => 6.18, 'postage' => 2.33 ], [ 'price' => 6.13, 'postage' => 0 ], [ 'price' => 4.19, 'postage' => 2.63 ], [ 'price' => 2.50, 'postage' => 1.80 ] ]; // add total element to arrays foreach ($data as &$a) { $a['total'] = $a['price'] + $a['postage']; } usort($data, function($a, $b) { return $a['price'] + $a['postage'] - $b['price'] - $b['postage']; }); echo '<pre>' . print_r($data, 1) . '</pre>'; // $data[1] and $data[2] are in wrong position ?> My results Array ( [0] => Array ( [price] => 2.5 [postage] => 1.8 [total] => 4.3 ) [1] => Array ( [price] => 6.13 [postage] => 0 [total] => 6.13 ) [2] => Array ( [price] => 4.19 [postage] => 2.63 [total] => 6.82 ) [3] => Array ( [price] => 6.18 [postage] => 2.33 [total] => 8.51 ) [4] => Array ( [price] => 8.5 [postage] => 3.5 [total] => 12 ) ) The order definitely looks correct. Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604723 Share on other sites More sharing options...
mac_gyver Posted January 16, 2023 Share Posted January 16, 2023 perhaps if the OP posts the incorrect result and points out what is wrong with it, it would provide a clue as to the problem. Â Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604727 Share on other sites More sharing options...
Barand Posted January 16, 2023 Share Posted January 16, 2023 How about it ^ @ChenXiu? I've shown you mine, you show me yours. Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604730 Share on other sites More sharing options...
ChenXiu Posted January 17, 2023 Author Share Posted January 17, 2023 (edited) Sure, no problem. Here is the script: <?php $data = [ [ 'price' => 8.50, 'postage' => 3.50 ], [ 'price' => 4.18, 'postage' => 0 ], [ 'price' => 5.25, 'postage' => .17 ], [ 'price' => 4.15, 'postage' => .02 ], [ 'price' => 2.50, 'postage' => 1.80 ] ]; usort($data, function($a, $b) { return $a['price'] + $a['postage'] - $b['price'] - $b['postage']; }); echo '<pre>' . print_r($data, 1) . '</pre>'; // $data[1] and $data[2] are in wrong position ?> Here is the result: <pre>Array ( [0] => Array ( [price] => 4.18 [postage] => 0 ) [1] => Array ( [price] => 4.15 [postage] => 0.02 ) [2] => Array ( [price] => 2.5 [postage] => 1.8 ) [3] => Array ( [price] => 5.25 [postage] => 0.17 ) [4] => Array ( [price] => 8.5 [postage] => 3.5 ) ) </pre> (I had to take some extra time to edit my post because the results are correct with certain numbers, but if I change certain digits, then the result will be wrong. It's "hit and miss" and I finally found some numeric values that produce the error. This error happens in both PHP 7.4, as well as PHP 8. The only way I got it to sort correctly is to get some chew toys and catnip and do: usort($data, function($a, $b) { $cat = $a['price'] + $a['postage']; $dog = $b['price'] + $b['postage']; if($cat > $dog) { $result = 1; } elseif ($cat < $dog) { $result = -1; } return $result; }); ***NEWSFLASH***EXTRA EXTRA READ ALL ABOUT IT ****** CHENXIU FINDS BUG IN PHP8 GETS AWARDED SCHOLARSHIP TO PHP ARRAY COLLEGE ******************* Edited January 17, 2023 by ChenXiu Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604737 Share on other sites More sharing options...
kicken Posted January 17, 2023 Share Posted January 17, 2023 (edited) 1 hour ago, ChenXiu said: ***NEWSFLASH***EXTRA EXTRA READ ALL ABOUT IT ****** CHENXIU FINDS BUG IN PHP8 GETS AWARDED SCHOLARSHIP TO PHP ARRAY COLLEGE *******************  This is not a bug, but a limitation on how floating point numbers get represented in binary. Some number cannot be perfectly represented so you end up with a close but not exact approximation. As you do math with these close but not perfect numbers, the error can accumulate enough to cause issues. The classic example is adding 0.1 and 0.2. echo (0.1+0.2 === 0.3)?'Matching':'Not a match'; If you run that, you'll get the Not a match message despite your expectations. This is due to the error accumulation of the math. You can see the real result if you serialze the equation. echo serialize(0.1+0.2); The result of that equation is actually 0.30000000000000004. In your case, the two arrays in question should be 0.01 difference, but the math ends up giving a difference of 0.00999999999999936 instead. I think the clearest way to solve the issue here is to add the two price/postage keys then round them to a precision of 2 and then compare them. Solves the precision issue and reads easier. usort($data, function($a, $b) { $aTotal=round($a['price']+$a['postage'],2); $bTotal=round($b['price']+$b['postage'],2); return $aTotal <=> $bTotal; });  Edited January 17, 2023 by kicken Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604739 Share on other sites More sharing options...
mac_gyver Posted January 17, 2023 Share Posted January 17, 2023 or use BC (BCD - Binary Coded Decimal) math - https://www.php.net/manual/en/ref.bc.php  Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604741 Share on other sites More sharing options...
kicken Posted January 17, 2023 Share Posted January 17, 2023 On second examination, while the floating point limitations are something to consider, I think the issue here is simpler. usort expects the function to return an integer. As a result the small difference is simply being rounded to 0, and 0 means the two entries are considered equal. The reason your re-write works is because you're using 1 / -1 (but not accounting for 0/equal which is something to be fixed) and mine works because it uses the spaceship operator which returns an appropriate integer value. Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604746 Share on other sites More sharing options...
Barand Posted January 17, 2023 Share Posted January 17, 2023 Oops! 🥵 Hence the success with the *100 fix. Gives weight to the definition of test data : That data for which the code works. Quote Link to comment https://forums.phpfreaks.com/topic/315790-sort-array-based-on-sum-of-2-values/#findComment-1604755 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.