0
\$\begingroup\$
function order_ignore_the($a, $b){
     // orders sentences ascending alphabetically, ignoring the  work "the"
     $args = func_get_args();
     foreach($args as $k=>$v){
          
          $sort = explode(" ",$v);
          $args[$k] = (strtolower($sort[0]) == "the" ? $sort[1] : $sort[0]);
     }
     
    return strcmp($args[0], $args[1]);
}

usort($array_of_sentences,'order_ignore_the');
\$\endgroup\$

3 Answers 3

1
\$\begingroup\$

I'm not sure what you're doing there, but I think it can get shortened to this.

function order_ignore_the($a, $b) {
    return strcmp(
        strcasecmp(substr($a, 0, 3), "the") != 0 ? $a : substr($a, 3),
        strcasecmp(substr($b, 0, 3), "the") != 0 ? $b : substr($b, 3)
    );
}

Be warned that this is not tested.

Edit: Long version with explanation:

function order_ignore_the($a, $b) {
    // Variables for later use
    $checkedA = $a;
    $checkedB = $b;

    // Compare the first three letters case-insensitive against "the"
    if(strcasecmp(substr($checkedA, 0, 3), "the") == 0) {
        // strip the "the" from the string
        $checkedA = substr($checkedA, 3);
    }
    // Repeate for $b
    if(strcasecmp(substr($checkedB, 0, 3), "the") == 0) {
        $checkedB = substr($checkedB, 3);
    }

    // Compare both strings
    return strcmp($checkedA, $checkedB);
}

Yes, it's swapped, I'm checking in the short version if the string does not match "the", and here I'm checking if it does match.

\$\endgroup\$
2
\$\begingroup\$

With some testing, it should look like the below

function order_ignore_the($a, $b) {
    return strcasecmp(
        strcasecmp(substr($a, 0, 4), "the ") != 0 ? $a : substr($a, 4),
        strcasecmp(substr($b, 0, 4), "the ") != 0 ? $b : substr($b, 4)
    );
}

Main differences being:

  • Widening the search for "the" to include the space after. Otherwise, you're matching on things like "theater", etc.
  • The last substr should likewise have start position 4. Otherwise, you're comparing on the space after "the".
  • You'll want the main comparison to ignore capitalization, too.
\$\endgroup\$
1
\$\begingroup\$

I took a moment to compile a list of real movie titles which represent some squirrelly fringe cases.

I arrived at a one-liner that relies on regex for best accuracy that doesn't fail when the leading The word is not immediately followed by a space. Notice that one real movie title below starts with the word "the", but the fourth character is not a space, so your exploding technique will not accurately remove it.

Your custom function explodes on spaces and assumes that all titles will contain at least one space -- this is a falsehood. Your code will generate Warning: Undefined array key 1 errors every time it encounters a movie without a space.

Another problem with your use of explode() is that you are not limiting the generated output to 2 elements. This will lead to incorrect results when comparing The Matrix, The Matrix 2, and The Matrix 3. Effectively, the The words will be stored as [0], then the word Matrix as [1], and any/all subsequent characters in the title are doomed to go unused.

Note, because you are using func_get_args() in your custom function and you never reference $a or $b, you don't actually need to declare them as arguments for your script to run.

Effectively, the preg_replace() call trims off the qualifying The in the temporary array which is only used for sorting the original array.

While regex is generally a more expensive technique than non-regex techniques, it never revisits any values because it is not called within the sorting iterations.

This snippet will deliver a much more accurate sort than the code you have posted.

Code: (Demo)

$array = [
   'The Theory of Everything',
   'The Mummy Returns',
   'The Mummy',
   'Then Came You',
   'The One',
   'The',
   'The 100',
   'The Matrix',
   'Theft',
   'The...',
   '300',
   'The 300 Spartans',
   'Mad Max',
   'Then',
   'The Martian',
];

array_multisort(preg_replace('/^the\b ?/i', '', $array), $array);
var_export($array);

Output:

array (
  0 => 'The',
  1 => 'The...',
  2 => 'The 100',
  3 => '300',
  4 => 'The 300 Spartans',
  5 => 'Mad Max',
  6 => 'The Martian',
  7 => 'The Matrix',
  8 => 'The Mummy',
  9 => 'The Mummy Returns',
  10 => 'The One',
  11 => 'Theft',
  12 => 'Then',
  13 => 'Then Came You',
  14 => 'The Theory of Everything',
)
\$\endgroup\$
1
  • \$\begingroup\$ I must have gotten stuck in my own head about using movie titles instead of "sentences". Sample data in the question would have helped me. Anyhow, my guidance still sings true. \$\endgroup\$ Jan 29, 2021 at 21:18

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.