Jump to content

multi-sort array with numbers with both columns Desc


wadesmart

Recommended Posts

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

Link to comment
Share on other sites

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>";

Link to comment
Share on other sites

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

 

 

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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;
}

Link to comment
Share on other sites

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>";
			}
		?>	

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.