Reputation: 4819
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?
Upvotes: 5
Views: 2204
Reputation: 776
The accepted answer isn't ideal, and actually incorrect as it does not preserve key/value pairings or result in the output the OP posted. An easier way to do this would be the following:
function sortAndUnique($array)
{
arsort($array);
$array = array_count_values($array);
arsort($array, SORT_NUMERIC);
return $array;
}
var_export(sortAndUnique($array));
Output:
array (
'f' => 2,
'b' => 2,
's' => 1,
'h' => 1,
'g' => 1,
'e' => 1,
'd' => 1,
'c' => 1,
'a' => 1,
)
This first alphabetizes the array, then sorts by most frequently occurring values, then sorts those values numerically.
Upvotes: 3
Reputation: 38436
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!
Upvotes: 3
Reputation: 13196
I'd recommend first word counting it, and then rebuilding an array based on the item counts.
The following rudimentary snippet may be useful to you. It does what you wish, though I'd question the use of inefficiently creating as many arrays as the final loop does for anything but trivial cases.
$array = array('s', 'h', 'c', 'b', 'a', 'b', 'd', 'e', 'f', 'f', 'g');
$counts = array();
foreach ($array as $v)
{
$counts[$v]++;
}
arsort($counts);
$array = array();
foreach ($counts as $k => $v)
{
// $array = array_merge($array, array_fill(0, $v, $k));
// ok, remove duplicates
$array[] = $v;
}
print_r($array);
Output:
Warning: Undefined array key "s"
Warning: Undefined array key "h"
Warning: Undefined array key "c"
Warning: Undefined array key "b"
Warning: Undefined array key "a"
Warning: Undefined array key "d"
Warning: Undefined array key "e"
Warning: Undefined array key "f"
Warning: Undefined array key "g"
Array
(
[0] => 2
[1] => 2
[2] => 1
[3] => 1
[4] => 1
[5] => 1
[6] => 1
[7] => 1
[8] => 1
)
Upvotes: 1
Reputation: 47904
To maintain the original value order among values sorted by number of occurrences, use the following.
Sorting the result from array_count_values()
will not preserve the original order of values. After removing duplicates, use usort()
to "stable sort" the values in descending order of occurrences.
Code: (Demo)
$array = ['s', 'h', 'c', 'b', 'a', 'b', 'd', 'e', 'f', 'f', 'g'];
$counts = array_count_values($array);
$array = array_unique($array);
usort($array, fn($a, $b) => $counts[$b] <=> $counts[$a]);
var_export($array);
Output:
array (
0 => 'b',
1 => 'f',
2 => 's',
3 => 'h',
4 => 'c',
5 => 'a',
6 => 'd',
7 => 'e',
8 => 'g',
)
Upvotes: 0