0

I hope this is not a duplicate question; I have searched to no avail...

I am trying to sort an array of objects returned by a search. I want to sort the results as follows: If the "name" property of an object matches the search query, put it at the top. Next, if the "city" property matches the query, put those next. (I intend to add more criteria later.) So I'm not strictly comparing values, but rather comparing each object $a to the search query $q. The array is indeed being re-indexed, but not in the order I am expecting. What am I missing?

function cmp($a, $b) {
    global $q; // search query

    $query = strtolower($q);
    $name  = strtolower($a->getName()); // defined in class
    $city  = strtolower($a->getCity()); // defined in class

    if ($name == $query) {
      return -1;
    }

    elseif ($city == $query) {
       return -1;
    }

    return 0;
}

usort($cinemas, 'cmp'); // $cinemas is an array of objects
5
  • the cmp function has to return 3 things: less than (-1), equal (0), greater than (+1). you're only returning two things: -1 and 0 Commented Sep 3, 2014 at 18:40
  • Hmm... I tried adding another elseif returning 1, but the results are still ordered in the same way (matching city is not at the top). Commented Sep 3, 2014 at 18:56
  • Would you please give an example of your 'search query' array. i.e. array('name' => 'fred', 'city' => 'mycity') or is it a different format? Some sample data and expected results may be useful. Your comment 'matching city is not at the top' - I am not sure how that would come about. Commented Sep 3, 2014 at 19:01
  • Way over-simplified, but something like this. $cinemas: Array ( [0] => Cinema Object ( [name:protected] => Sample One [city:protected] => Grapevine ) [1] => Cinema Object ( [name:protected] => Sample Two [city:protected] => Flower Mound ) [2] => Cinema Object ( [name:protected] => Sample Three [city:protected] => TROPHY CLUB ) [3] => Cinema Object ( [name:protected] => Sample Four [city:protected] => Irving ) ) Commented Sep 3, 2014 at 19:24
  • And $q is a sanitized version of what the user typed in the search input. Commented Sep 3, 2014 at 19:27

2 Answers 2

1

You need to compare two items in your comparison function and return which one is greater. At the moment you're completely ignoring the second item being passed in, $b. Your logic needs to be, in this order:

  1. if both a's and b's name match the query, they're equal
  2. if a's name matches the query, it is greater
  3. if b's name matches the query, it is greater
  4. if both a's and b's city match the query, they're equal
  5. if a's city matches the query, it is greater
  6. if b's city matches the query, it is greater
  7. if a's name and b's name aren't equal, return the strcmp value of both
  8. return the strcmp value of a's city and b's city
Sign up to request clarification or add additional context in comments.

Comments

0

You should use an anonymous function:

usort($cinemas, function($a, $b) use ($q) {
    $query = strtolower($q);
    $name  = strtolower($a->getName()); // defined in class
    $city  = strtolower($a->getCity()); // defined in class

    // do the comparison
});

Note that $q was imported into the scope of the function, so there's no need for a global.

Apart from that, the function should return either 1, 0 or -1, as has been mentioned in the comments on the question.

2 Comments

The 'usort' function need to return one of 'three' values: -1 for 'less than', +1 for 'greater than; and zero for 'equal to'.
Thanks, fixed. (Although, in reality, -1 and 1 are usually sufficient.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.