0

For example, input array is [9,1,9,1,3,9,1,2,9] output array will be [9,9,9,9,1,1,1,2,3].

Here's what I've tried below but not giving me expected result:

$array = [9,1,9,1,3,9,1,2,9];
$values = array_count_values($array);
arsort($values);
$popular = array_keys($values);

print_r(array_values($popular));

foreach ($values as $key => $val) {
    echo $key.", ";
}

Output:

Array
(
    [0] => 9
    [1] => 1
    [2] => 3
    [3] => 2
)
9, 1, 3, 2,
  • I have tried using "array_count_values()" function in php but the problem is it prints only one case of the repeated element, I want all elements to print in order of frequency. Thanks in advance guys... – Informal Joke Jul 03 '19 at 13:44
  • Please visit [help center](https://stackoverflow.com/help/minimal-reproducible-example) to learn how to create a minimal, reproducible question. You should not be explaining the whole question in header and you should show what you have tried so far. – DjSh Jul 03 '19 at 13:49
  • @DjSh Thanks for your response.. I've tried it severally but no way out yet... Please help out if you can.. Thanks – Informal Joke Jul 03 '19 at 13:52
  • we need to see your code – DjSh Jul 03 '19 at 13:54
  • Check, I have updated with my code.. thank you – Informal Joke Jul 03 '19 at 14:02
  • Any idea yet please..? – Informal Joke Jul 03 '19 at 14:11

3 Answers3

1

If we loop the array_count_values then we can make sure they come in the correct order.
When there is two that is the same count I find all the same with array_intersect then foreach them and add in the correct order.

$array = [9,1,9,1,3,9,1,2,9];
$values = array_count_values($array);
arsort($values);
//var_dump($values);

$result =[];
$same = [];
foreach($values as $key => $val){
    if(!in_array($key, array_keys($same))){
        if(next($values) != $val){
            $result = array_merge($result, array_fill(0, $val, $key));
        }else{
            $same = array_intersect($values, [$val]);
            ksort($same);
            foreach($same as $skey => $val){
                $result = array_merge($result, array_fill(0, $val, $skey));
            }
            //var_dump($same);
        }
    }
}

var_dump($result);

https://3v4l.org/sk44Q

Andreas
  • 23,610
  • 6
  • 30
  • 62
0

Try usort combined with array_count (php >= 7.0):

$array = [9,1,9,1,3,9,1,2,9];

$arrayCounts = array_count_values($array);

usort($array, function ($a, $b) use ($arrayCounts) {
    $countA = $arrayCounts[$a] ?? 0;
    $countB = $arrayCounts[$b] ?? 0;
    if ($countA == $countB) {
       return $a == $b ? 0 : ($a < $b ? -1 : 1);
    }
    return ($countA > $countB) ? -1 : 1;
});
marv255
  • 808
  • 6
  • 19
  • Thanks marv255, it's still not working.. Have you tried it? – Informal Joke Jul 03 '19 at 14:12
  • @InformalJoke [example](http://sandbox.onlinephpfunctions.com/code/2bb3f00232de72ba591696d6ea99cd3168186368). – marv255 Jul 03 '19 at 14:17
  • I think the 2 and 3 at the end are the wrong way round. – Nigel Ren Jul 03 '19 at 14:19
  • @InformalJoke. Yes forgot about asc. Update answer with fixed function and [fixed example](http://sandbox.onlinephpfunctions.com/code/6808a3b9318aa2b5d180a0824e4cd76f32a8d6b6). – marv255 Jul 03 '19 at 14:20
  • Wow, works like magic now... But I'm lost honestly, the code is complex... any explanation please. Thank you very very much... and I would love to connect with you and learn, twitter handle or any means ?... thanks again.. – Informal Joke Jul 03 '19 at 14:31
0

You could use this sequence:

$arrayCounts = array_count_values($array);
usort($array, function ($a, $b) use ($arrayCounts) {
    return $arrayCounts[$b] - $arrayCounts[$a] ?: $a - $b; 
});

Now $array is sorted as requested.

The callback function that is passed as argument to usort should return a negative number when the two elements $a and $b should stay in that order (from left to right), or a positive number when they should be reversed. 0 when it does not matter.

The numeric expression that is returned in this particular callback function subtracts the frequencies of $a and $b. If $b occurs more, then that subtraction is positive, and that is returned. Similarly if the subtraction is negative, then that negative value is returned. Now when the frequencies are equal, the ?: operator kicks in and the expression after it is evaluated. That other subtraction also results in a positive or negative value, based on the original value itself. So $a - $b will be negative when $a < $b, which means the order can remain as it is (knowing that we already derived that their frequencies were equal).

trincot
  • 317,000
  • 35
  • 244
  • 286
  • Wow.. working fine, but not in ascending order for same frequency element yet... Thanks alot.. I think I need to learn this usort concept.. Thanks again... – Informal Joke Jul 03 '19 at 14:36
  • I edited my answer. It seems to order ascending for same frequency. – trincot Jul 03 '19 at 14:37
  • Also added an explanation of what this callback function passed to `usort` is doing. – trincot Jul 03 '19 at 14:43
  • For PHP 7+, you could use the spaceship operator `<=>`. – nice_dev Jul 03 '19 at 14:45
  • @vivek_23, true, although I find that less useful for numeric data. A minus sign is two characters less than the spaceship ;-) – trincot Jul 03 '19 at 14:47
  • @trincot Haha, ok :) But it wouldn't make much computational difference and makes your code cleaner(although the reader needs to know about it beforehand). – nice_dev Jul 03 '19 at 14:50
  • @trincot Thanks alot sir, it works just fine now... Please is there a way I can connect with you, are you on twitter..? Thanks a lot – Informal Joke Jul 03 '19 at 15:02
  • You can just drop a comment in a comment box with my name, and I'll respond. My profile mentions a mail adres, but I don't monitor it daily. – trincot Jul 03 '19 at 15:35