phparrayssortingduplicatescustom-sort

Stable sort the unique values of a flat array by their original occurrences count in a descending direction


I'd like to order an array by the number of times each member turns up, then remove duplicates.

So this:

$array = array('s', 'h', 'c', 'b', 'a', 'b', 'd', 'e', 'f', 'f', 'g')

Would first be ordered:

['b', 'b', 'f', 'f', 's', 'h', 'c', 'a', 'd', 'e', 'g']

And then have the duplicates removed:

$array = array_unique($array);

And look like this:

['b', 'f', 's', 'h', 'c', 'a', 'd', 'e', 'g']

So, how do I do this?


Solution

  • A quick way to do it would be to build an array/map that counts each instance of each letter/entry in the original array, sorts the counted one, and then gets the unique values (in order) from the sorted list.

    An example implementation would be:

    <?php
    $unsorted = array('a', 'b', 'c', 'b', 'd', 'e', 'f', 'f', 'g');
    
    // build an array that "counts" each instance/entry
    $count = array();
    foreach ($unsorted as $key) {
        if (!isset($count[$key])) $count[$key] = 0;
        $count[$key]++;
    }
    // sort the counted array in reverse order (to be "descending")
    arsort($count, SORT_NUMERIC);
    
    // copy each of the keys of `$count`, in-order, into a new array
    $sorted = array();
    foreach ($count as $key=>$count) $sorted[] = $key;
    
    print_r($sorted);
    ?>
    

    This gives the output:

    Array
    (
        [0] => b
        [1] => f
        [2] => s
        [3] => h
        [4] => c
        [5] => a
        [6] => d
        [7] => e
        [8] => g
    )
    

    This does not preserve the order of which letter(s) it sees first, it really just sorts them based on the number of times they're in the original array. It could be modified with additional logic to add some other sort-functionality say, to sort alphabetically after sorting by instances.

    Edit: The function array_count_values(), used such as $count = array_count_values($unsorted), could replace the whole "counting" loop from above. The output from that function is the exact same as is produced by my loop. Thanks to @Ana for that hint!