wadesmart Posted August 29, 2012 Share Posted August 29, 2012 Im looking to sort team stats by points and goals. I thought I was onto something but Ive hit a spot I get around. Below Ive posted the file I pull from, the code and two sets of results. My intended end result would show: Dk Blue 1 1 0 0 3 10 White 1 1 0 0 3 9 Lt Blue 1 1 0 0 3 8 Green 1 0 1 0 0 8 Purple 1 0 1 0 0 5 Yellow 1 0 1 0 0 4 teamstats.txt: Dk_Blue 1 1 0 0 3 10 Green 1 0 1 0 0 8 Lt_Blue 1 1 0 0 3 8 Purple 1 0 1 0 0 5 White 1 1 0 0 3 9 Yellow 1 0 1 0 0 4 <?php $stats = file('teamstats.txt'); foreach($stats as $line_number => $line){ $l = explode(" ",$line); $newarray[$line_number]["team"] = $l[0]; $newarray[$line_number]["games"] = $l[1]; $newarray[$line_number]["wins"] = $l[2]; $newarray[$line_number]["loses"] = $l[3]; $newarray[$line_number]["ties"] = $l[4]; $newarray[$line_number]["points"] = $l[5]; $newarray[$line_number]["goals"] = $l[6]; } foreach($newarray as $key => $row){ $team[$key] = $row['team']; $games[$key] = $row['games']; $win[$key] = $row['wins']; $loses[$key] = $row['loses']; $ties[$key] = $row['ties']; $points[$key] = $row['points']; $goals[$key] = $row['goals']; } array_multisort($points, SORT_DESC, $goals, SORT_DESC, $newarray); $count = count($newarray); print"<table> <tr> <th>Team</th> <th>Games</th> <th>Wins</th> <th>Loses</th> <th>Ties</th> <th>Points</th> <th>Goals</th> </tr>"; for($i = 0; $i < $count; $i++){ print" <tr> <td>".$newarray[$i]["team"]."</td> <td>".$newarray[$i]["games"]."</td> <td>".$newarray[$i]["wins"]."</td> <td>".$newarray[$i]["loses"]."</td> <td>".$newarray[$i]["ties"]."</td> <td>".$newarray[$i]["points"]."</td> <td>".$newarray[$i]["goals"]."</td> </tr>"; } print"</table>"; ?> Results: When I run ONLY Team, Points & Goals sorting on points and goals I have this result: Team Points Goals Dk Blue 3 10 White 3 9 Lt Blue 3 8 Green 0 8 Purple 0 5 Yellow 0 4 When I sort on all as in the code above but still sorting only points and goals I have this result: Team Games Wins Loses Ties Points Goals White 1 1 0 0 3 9 Lt_Blue 1 1 0 0 3 8 Dk_Blue 1 1 0 0 3 10 Green 1 0 1 0 0 8 Purple 1 0 1 0 0 5 Yellow 1 0 1 0 0 4 I found a function on http://www.the-art-of-web.com/php/sortarray/ that used this code <?PHP function compare_fullname($a, $b) { $retval = strnatcmp($a['lastname'], $b['lastname']); if(!$retval) return strnatcmp($a['firstname'], $b['firstname']); return $retval; } // sort alphabetically by firstname and lastname usort($data, 'compare_fullname'); ?> to do something similar on names but, the problem with usort which I found out very quickly is, "If two members compare as equal, their relative order in the sorted array is undefined."- php.net Any suggestion as to how to get these in the order I seek? Thanks Wade Quote Link to comment https://forums.phpfreaks.com/topic/267751-multi-sort-array-with-numbers-with-both-columns-desc/ Share on other sites More sharing options...
xyph Posted August 29, 2012 Share Posted August 29, 2012 Have you tried array_multisort? http://php.net/array_multisort Check out example 3, and let us know if you have any problems Quote Link to comment https://forums.phpfreaks.com/topic/267751-multi-sort-array-with-numbers-with-both-columns-desc/#findComment-1373572 Share on other sites More sharing options...
wadesmart Posted August 29, 2012 Author Share Posted August 29, 2012 You mean this array_multisort found my code that I posted? array_multisort($points, SORT_DESC, $goals, SORT_DESC, $newarray); Yes I did. Quote Link to comment https://forums.phpfreaks.com/topic/267751-multi-sort-array-with-numbers-with-both-columns-desc/#findComment-1373667 Share on other sites More sharing options...
Psycho Posted August 29, 2012 Share Posted August 29, 2012 There is a much simpler solution. But first, be sure to start reading the manual. When you are looking up a particular function look at the related functions. You will learn a lot and find more efficient way to do things. For example this: foreach($stats as $line_number => $line){ $l = explode(" ",$line); $newarray[$line_number]["team"] = $l[0]; $newarray[$line_number]["games"] = $l[1]; $newarray[$line_number]["wins"] = $l[2]; $newarray[$line_number]["loses"] = $l[3]; $newarray[$line_number]["ties"] = $l[4]; $newarray[$line_number]["points"] = $l[5]; $newarray[$line_number]["goals"] = $l[6]; } Could be replaced with this: $keys = array('team', 'games', 'wins', 'loses', 'ties', 'points', 'goals'); foreach($stats as $line_number => $line) { $newarray[$line_number] = array_combine($keys, explode(' ',$line)); } As to your sorting problem, I always found array_multisort() to be problematic because you have to convert the array first. Instead usort() is much easier to use. As per your comment "If two members compare as equal, their relative order in the sorted array is undefined."- php.net Is correct. But, that would be true for ANY sorting method. That is why it is up to YOU to determine ALL of the sorting criteria. So, in your function to use with usort() you need to defined the first field to use for sorting. If the two values for that field are equal you need to define another field to use, and so on and so on. I "fixed" some of your existing code below and implemented a function to use with usort() that will forst sort on points, then by goals. You can easily add additional sorting criteria as you see fit. I think I used the right comparison to sort descending, but if not just change the "<" to ">" in the function. //Function to sort the stats function sortStats($a, $b) { //Sort by points if($a['points'] != $b['points']) { return ($a['points'] < $b['points']) ? 1 : -1; } //Sort by goals if($a['goals'] != $b['goals']) { return ($a['goals'] < $b['goals']) ? 1 : -1; } //Both points & gaols are the same return 0; } $stats_file = file('teamstats.txt'); //Process file data into an array $keys = array('team', 'games', 'wins', 'loses', 'ties', 'points', 'goals'); $stats = array(); foreach($stats_file as $line_number => $line) { $stats[$line_number] = array_combine($keys, explode(' ',$line)); } //Sort the stats usort($stats, 'sortStats'); echo "<table> <tr> <th>Team</th> <th>Games</th> <th>Wins</th> <th>Loses</th> <th>Ties</th> <th>Points</th> <th>Goals</th> </tr>"; foreach($stats as $team) { echo "<tr> <td>{$team['team']}</td> <td>{$team['games']}</td> <td>{$team['wins']}</td> <td>{$team['loses']}</td> <td>{$team['ties']}</td> <td>{$team['points']}</td> <td>{$team['goals']}</td> </tr>"; } echo "</table>"; Quote Link to comment https://forums.phpfreaks.com/topic/267751-multi-sort-array-with-numbers-with-both-columns-desc/#findComment-1373694 Share on other sites More sharing options...
Barand Posted August 29, 2012 Share Posted August 29, 2012 you can simplify that to function sortStats($a, $b) { if ($a['points'] == $b['points']) { return $b['goals'] - $a['goals']; // DESC sort } else return $b['points'] - $a['points']; // DESC sort } Quote Link to comment https://forums.phpfreaks.com/topic/267751-multi-sort-array-with-numbers-with-both-columns-desc/#findComment-1373705 Share on other sites More sharing options...
wadesmart Posted August 29, 2012 Author Share Posted August 29, 2012 Ok. I ran the code you posted with this result: Team Games Wins Loses Ties Points Goals White 1 1 0 0 3 9 Lt_Blue 1 1 0 0 3 8 Dk_Blue 1 1 0 0 3 10 Green 1 0 1 0 0 8 Purple 1 0 1 0 0 5 Yellow 1 0 1 0 0 4 Quote Link to comment https://forums.phpfreaks.com/topic/267751-multi-sort-array-with-numbers-with-both-columns-desc/#findComment-1373711 Share on other sites More sharing options...
wadesmart Posted August 29, 2012 Author Share Posted August 29, 2012 I changed your <> around function sortStats($a, $b) { //Sort by points if($a['points'] != $b['points']) { return ($a['points'] < $b['points']) ? 1 : -1; } //Sort by goals if($a['goals'] != $b['goals']) { return ($a['goals'] > $b['goals']) ? 1 : -1; } //Both points & gaols are the same return 0; } That produces this: Team Games Wins Loses Ties Points Goals Dk_Blue 1 1 0 0 3 10 Lt_Blue 1 1 0 0 3 8 White 1 1 0 0 3 9 Yellow 1 0 1 0 0 4 Purple 1 0 1 0 0 5 Green 1 0 1 0 0 8 Quote Link to comment https://forums.phpfreaks.com/topic/267751-multi-sort-array-with-numbers-with-both-columns-desc/#findComment-1373716 Share on other sites More sharing options...
xyph Posted August 29, 2012 Share Posted August 29, 2012 The issue was that you were using the string versions of your numbers. If you forced multisort to use SORT_NUMERIC or you casted your comparison values to integers, it would've worked as you expected. <?php $data = 'Dk_Blue 1 1 0 0 3 10 Green 1 0 1 0 0 8 Lt_Blue 1 1 0 0 3 8 Purple 1 0 1 0 0 5 White 1 1 0 0 3 9 Yellow 1 0 1 0 0 4'; $lines = explode("\n",$data); $stats = array(); $sort1 = array(); $sort2 = array(); foreach( $lines as $key => $line ) { $values = explode(' ',$line); $stats[$key]['team'] = $values[0]; $stats[$key]['points'] = $values[5]; $stats[$key]['goals'] = $values[6]; $sort1[$key] = (int)$values[6]; $sort2[$key] = (int)$values[5]; } header('content-type: text/plain'); foreach($stats as $arr) echo "$arr[team]\t$arr[points]\t$arr[goals]\n"; array_multisort($sort1, SORT_DESC, $sort2, SORT_DESC, $stats); echo "\n"; foreach($stats as $arr) echo "$arr[team]\t$arr[points]\t$arr[goals]\n"; ?> Dk_Blue 3 10 Green 0 8 Lt_Blue 3 8 Purple 0 5 White 3 9 Yellow 0 4 Dk_Blue 3 10 White 3 9 Lt_Blue 3 8 Green 0 8 Purple 0 5 Yellow 0 4 Quote Link to comment https://forums.phpfreaks.com/topic/267751-multi-sort-array-with-numbers-with-both-columns-desc/#findComment-1373717 Share on other sites More sharing options...
wadesmart Posted August 29, 2012 Author Share Posted August 29, 2012 Doesnt sort numeric start at 0 and go up? Team Games Wins Loses Ties Points Goals Yellow 1 0 1 0 0 4 Purple 1 0 1 0 0 5 Green 1 0 1 0 0 8 Lt_Blue 1 1 0 0 3 8 White 1 1 0 0 3 9 Dk_Blue 1 1 0 0 3 10 This is what I want but in reverse. Quote Link to comment https://forums.phpfreaks.com/topic/267751-multi-sort-array-with-numbers-with-both-columns-desc/#findComment-1373718 Share on other sites More sharing options...
Psycho Posted August 29, 2012 Share Posted August 29, 2012 You could use array_walk() or array_map() to convert all the numeric strings to integers, or just use strnatcmp() in the comparison function for usort() - see solution below. As I stated above, read the manual. I didn't specifically know about strnatcmp() until about 5 minutes ago. But, I went to the manual and found it. function sortStats($a, $b) { //Sort by points if($a['points'] != $b['points']) { return strnatcmp($b['points'], $a['points']); } //Sort by goals if($a['goals'] != $b['goals']) { return strnatcmp($b['goals'], $a['goals']); } //Both points & goals are the same return 0; } Quote Link to comment https://forums.phpfreaks.com/topic/267751-multi-sort-array-with-numbers-with-both-columns-desc/#findComment-1373720 Share on other sites More sharing options...
wadesmart Posted August 30, 2012 Author Share Posted August 30, 2012 Or just $newarray = array_reverse($newarray); Quote Link to comment https://forums.phpfreaks.com/topic/267751-multi-sort-array-with-numbers-with-both-columns-desc/#findComment-1373734 Share on other sites More sharing options...
Psycho Posted August 30, 2012 Share Posted August 30, 2012 Or just $newarray = array_reverse($newarray); Um, no. He want to order the elements of the array by two different values in the sub arrays. How on earth is array_reverse() going to accomplish that? Quote Link to comment https://forums.phpfreaks.com/topic/267751-multi-sort-array-with-numbers-with-both-columns-desc/#findComment-1373747 Share on other sites More sharing options...
wadesmart Posted August 30, 2012 Author Share Posted August 30, 2012 While not as streamlined as your code, this went live last night. Thanks for all the help. I appreciate it. <?php $stats = file('./docs/teamstats.txt'); foreach($stats as $line_number => $line){ $l = explode(" ",$line); $newarray[$line_number]["team"] = $l[0]; $newarray[$line_number]["games"] = $l[1]; $newarray[$line_number]["wins"] = $l[2]; $newarray[$line_number]["loses"] = $l[3]; $newarray[$line_number]["ties"] = $l[4]; $newarray[$line_number]["points"] = $l[5]; $newarray[$line_number]["goals"] = $l[6]; } foreach($newarray as $key => $row){ $team[$key] = $row['team']; $games[$key] = $row['games']; $win[$key] = $row['wins']; $loses[$key] = $row['loses']; $ties[$key] = $row['ties']; $points[$key] = $row['points']; $goals[$key] = $row['goals']; } array_multisort($points, SORT_NUMERIC, $goals, SORT_NUMERIC, $newarray); $newarray = array_reverse($newarray); $count = count($newarray); for($i = 0; $i < $count; $i++){ print" <tr> <td>".$newarray[$i]["team"]."</td> <td>".$newarray[$i]["games"]."</td> <td>".$newarray[$i]["wins"]."</td> <td>".$newarray[$i]["loses"]."</td> <td>".$newarray[$i]["ties"]."</td> <td>".$newarray[$i]["points"]."</td> <td>".$newarray[$i]["goals"]."</td> </tr>"; } ?> Quote Link to comment https://forums.phpfreaks.com/topic/267751-multi-sort-array-with-numbers-with-both-columns-desc/#findComment-1373822 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.