Jump to content

Help sorting an array by two arguments


charlysole

Recommended Posts

Hi everyone

This is quite difficult to explain....

i have the following code:
     // Calculate total ordinal ranking.
      uasort($totals, "sort_totals");
      $ordinal = 0;
      $last_ordinal = 0;
      $high_score = 0;
      $last_score = 100000;
      foreach ($totals as $uid => $u_object) {
        $ordinal++;
        if ($u_object['total'] < $last_score) {
          $last_ordinal = $ordinal;
          $last_score = $u_object['total'];
          if ( $ordinal == 1 ) {
            $high_score = $last_score;
          }
        }
        $totals[$uid]['ranking'] = $last_ordinal;
        $totals[$uid]['pts_back'] = $high_score - $last_score;
      }
      cache_set($cache_key, $totals);
    }
    $cache_totals[$cache_key] = $totals;
  }


  return $cache_totals[$cache_key];
}
function sort_totals($a, $b) {
  if ($a['total'] > $b['total']) {
    return -1;
  }
  elseif ($a['total'] < $b['total']) {
      return 1;
  }
  else {
    if ($a['name'] < $b['name']) {
      return -1;
    }
    elseif ($a['name'] > $b['name']) {
        return 1;
    }
    else {
      return 0;
    }
  }
}

This code sorts the totals arranging them major to minor. And thats ok... it works.

 

Now I also have another parameter called "exact" here: .... $u_object['exact'] 

Who contains an integer showing the number of times a user has matched the exact result.

 

What i want to do is use
$u_object['exact'] 

as a second arrangement parameter number...

 

Example

For the following stored data:

User 1:  100 points, and 4 matches.

User 2:  90  points, and 2 matches.

User 4: 100 points and 7 matches.

 

The result should be:

User 4: 100 points and 7 matches.

User 1:  100 points, and 4 matches.

User 2:  90  points, and 2 matches.

 

As you can see 2 the first sort is by total, and the second by matches

 

How can i do this?

 

Thanks in advice.

And sorry for my poor english!

 

 

Link to comment
Share on other sites

$u_object is the same array as $a and $b in the comparison function (sort_totals). You have some branching logic in there to handle [total] and [name] so all you have to do is extend it with another comparison using [exact] in between.

 

function sort_totals($a, $b) {
  if ($a['total'] > $b['total']) {
    return -1;
  }
  elseif ($a['total'] < $b['total']) {
      return 1;
  }
  else {
    if ($a['exact'] > $b['exact']) {
      return -1;
    }
    elseif ($a['exact'] < $b['exact']) {
      return 1;
    }
    else {
      if ($a['name'] < $b['name']) {
        return -1;
      }
      elseif ($a['name'] > $b['name']) {
          return 1;
      }
      else {
        return 0;
      }
    }
  }
}
Getting rather long, though, isn't it? The good news is that there's a much better way of doing all those comparisons, and it's possible because the return value from the function merely has to be negative, zero, or positive - not strictly -1, 0, or 1.

 

For the numbers, you can replace "if $x strcmp. However both of those will immediately return 0 if the two values are the same, when you need it to do the next comparison instead. You can use the ternary operator ?: for this, using the first value if it is truthy (non-zero) and the second value if it is false-y (zero).

 

If that made even a little bit of sense, great. Here's the code:

function sort_totals($a, $b) {
  return ($b['total'] - $a['total']) // higher total first
      ?: ($b['exact'] - $a['exact']) // or else higher exact first
      ?: strcmp($a['name'], $b['name']) // or else name in alphabetical order
  ;
}
If you understand the deal with using subtraction/strcmp() then it's easier to add more conditions in here too - though you're probably not likely to need to do that.
Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • 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.