70

I made an anagram machine and I have an array of positive matches. The trouble is they are all in a different order, I want to be able to sort the array so the longest array values appear first.

Anybody have any ideas on how to do this?

12 Answers 12

164

Use https://www.php.net/manual/en/function.usort.php

with this custom function

function sortByLength($a,$b){
    return strlen($b)-strlen($a);
}

usort($array,'sortByLength');

Use uasort if you want to keep the old indexes, use usort if you don't care.

Also, I believe that my version is better because usort is an unstable sort.

$array = array("bbbbb", "dog", "cat", "aaa", "aaaa");
// mine
[0] => bbbbb
[1] => aaaa
[2] => aaa
[3] => cat
[4] => dog

// others
[0] => bbbbb
[1] => aaaa
[2] => dog
[3] => aaa
[4] => cat
Sign up to request clarification or add additional context in comments.

8 Comments

This is good, though I wouldn't call the function just 'sort'. sortByLength below is more descriptive.
to all - remember about mb_strlen() - not all langs are same
No Brian, the function's job is not to sort, but to compare. Therefore I would call it compareStrLengthNegatively
Not naming it "sort" is important, not because of descriptiveness, but because of fatal error: cannot redeclare sort.
Why not use mb_strlen instead of strlen? Although slower than strlen, it will prevent headache once multi-byte value occurs.
|
65

If you'd like to do it the PHP 5.3 way, you might want to create something like this:

usort($array, function($a, $b) {
    return strlen($b) - strlen($a);
});

This way you won't pollute your global namespace.

But do this only if you need it at a single place in your source code to keep things DRY.

Comments

48

PHP7 is coming. In PHP7, you could use the Spaceship Operator.

usort($array, function($a, $b) {
    return strlen($b) <=> strlen($a);
});

Hope this could help you in the future.

1 Comment

Interesting, didn't know about that one. I wonder if it has any performance benefit to just using a subtraction instead like @clttj suggested.
11
function sortByLength($a,$b){
  if($a == $b) return 0;
  return (strlen($a) > strlen($b) ? -1 : 1);
}
usort($array,'sortByLength');

5 Comments

There's a bug in this. Your equality condition is too narrow. The strings "abc" and "def" should return 0 from this sort, but won't. They will instead return 1. And while I realize that this isn't a grave error (the output won't look broken, it's technically inaccurate.
'if($a == $b) return 0;' this is a mistake. We are talking about length.
@ Peter and Thinker, yes its an oddity of the PHP manual. I myself did strlen($a) == strlen($b), but then I saw that since PHP uses an unstable sort, it doesn't matter! It still messes up the order. So I came up with the shortest function that works.
Had it from some example based on the manual (as unknown said), didn't really bother to analyse that as I'm not into php lately, just checked if it works. Got sth better - good.
Yep, the manual examples and comments sometimes are very sad, but I don't know if it's really worth giving a damn :) Cheerz.
5

Descending Order:

$array = ['aa', 'bb', 'c', 'ccc', 'a', 'ertre'];

usort($array, function($a, $b){
   return strlen($a) < strlen($b);
});

var_export($array);

// Output
array (
  0 => 'ertre',
  1 => 'ccc',
  2 => 'aa',
  3 => 'bb',
  4 => 'c',
  5 => 'a',
)

Ascending Order:

$array = ['aa', 'bb', 'c', 'ccc', 'a', 'ertre'];

usort($array, function($a, $b){
   return strlen($a) > strlen($b);
});

// Output
array (
  0 => 'c',
  1 => 'a',
  2 => 'aa',
  3 => 'bb',
  4 => 'ccc',
  5 => 'ertre',
)

1 Comment

Why would anyone use this when the spaceship operator was recommended 5 years earlier on this page?
1
array_multisort(array_map('count', $arr), SORT_DESC, $arr);

Comments

1

Here is a snippet that demonstrates exactly why you should NOT use function calls inside of usort() -- you will be needlessly calling strlen() on values that were previously encountered.

In my 9-element array, array_multisort() calls strlen() 9 times, but usort() calls strlen() 23 times -- that's no bueno.

Code: (Demo)

function multisort($array) {
    array_multisort(array_map('strlen', $array), SORT_DESC, $array);
    printf(
        "Total strlen() calls: %d\n%s\n---\n",
        count($array),
        var_export($array, true)
    );
}

function usersort($array) {
    usort(
        $array,
        function($a, $b) {
            echo "strlen() called twice\n";
            return strlen($b) <=> strlen($a);
        }
    );
    var_export($array);
    echo "\n---\n";
}

multisort($array);
usersort($array);

Output (from my own sample array):

Total strlen() calls: 9
array (
  0 => 'eight',
  1 => 'seven',
  2 => 'three',
  3 => 'five',
  4 => 'four',
  5 => 'nine',
  6 => 'one',
  7 => 'six',
  8 => 'two',
)
---
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
strlen() called twice
array (
  0 => 'three',
  1 => 'seven',
  2 => 'eight',
  3 => 'four',
  4 => 'five',
  5 => 'nine',
  6 => 'one',
  7 => 'two',
  8 => 'six',
)
---

Comments

0

Make an array of strlen of oyur array elements, and multisort it with your array.

foreach($Yourarray as $c=>$key) {               
    $key['maxlen'] = strlen($key);  
    $sort_numcie[] = $key['maxlen'];
}

array_multisort($sort_numcie, $Yourarray);  

This will definately work. I am sure!

1 Comment

Naming a value $key is counterintuitive. Declaring associative element $key['maxlen'] immediately after declaring a scalar value as $key is just plain weird. $key['maxlen'] is frankly a useless variable declaration.
0

In addition to the accepted answer, to sort an array by length with ascending OR descending order:

function strlen_compare($a,$b){
    if(function_exists('mb_strlen')){
         return mb_strlen($b) - mb_strlen($a);
    }
    else{
         return strlen($b) - strlen($a);
    }
}

function strlen_array_sort($array,$order='dsc'){
    usort($array,'strlen_compare');
    if($order=='asc'){
        $array=array_reverse($array);
    }
    return $array;
}

Comments

0

Here's a way using the spaceship operator (needs PHP 7.0):

$arr = ['apple','pear','oranges','banana'];
usort($arr, function ($a, $b) { return (strlen($a) <=> strlen($b)); });
print_r($arr);

Comments

-1

Here's a way I've done it in the past.

// Here's the sorting...
$array = array_combine($words, array_map('strlen', $words));
arsort($array);

1 Comment

array with same value will be combined: array("aba", "aa", "ad", "vcd", "aba");
-8

It's simple.

function LSort(a,b){return a.length-b.length;}

var YourArray=[[1,2,3,4,5,6], ['a','b'], ['X','Y','Z'], ['I','Love','You'], ['good man']];

YourArray.sort(Lsort);

Result:

['good man'] Length=1
['a','b'] Length=3
['X','Y','Z'] Length=3
['I','Love','You'] Length=3
[1,2,3,4,5,6] Length=6

2 Comments

Please take a look at this Markdown help page to improve your formatting skills.
This is not even PHP.

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.