从包含相同值的数组中获取x最高值

I'm using the following code to retrieve the highest 3 numbers from an array.

$a = array(1,2,5,10,15,20,10,15);
arsort($a, SORT_NUMERIC);
$highest = array_slice($a, 0, 3);

This code correctly gives me the highest three numbers array(20,15,10); however, I'm interested in getting the highest 3 numbers including the ones that are identical. In this example, I'm expecting to get an array like array(10, 10, 15, 15, 20)

Might be simpler but my brain is tired. Use arsort() to get the highest first, count the values to get unique keys with their count and slice the first 3 (make sure to pass true to preserve keys):

arsort($a, SORT_NUMERIC);
$counts = array_slice(array_count_values($a), 0, 3, true);

Then loop those 3 and fill an array with the number value the number of times it was counted and merge with the previous result:

$highest = array();

foreach($counts as $value => $count) {
    $highest = array_merge($highest, array_fill(0, $count, $value));
}

You can use a function like this:

$a = array(1,2,5,10,15,20,10,15); //-- Original Array

function get3highest($a){
  $h = array(); //-- highest
  if(count($a) >= 3){ //-- Checking length
    $c = 0; //-- Counter
    while ($c < 3 || in_array($a[count($a)-1],$h) ){ //-- 3 elements or repeated value
      $max = array_pop($a);
      if(!in_array($max,$h)){
        ++$c;
      }
      $h[] = $max;
    }
    sort($h); //-- sorting
  }
  return $h; //-- values
} 
print_r(get3Highest($a));

Of course you can improve this function to accept a dinamic value of "highest" values.

The below function may be usefull

$a = array(1,2,5,10,15,20,10,15);
function getMaxValue($array,$n){ 
    $max_array = array(); // array to store all the max values
    for($i=0;$i<$n;$i++){ // loop to get number of highest values 
        $keys = array_keys($array,max($array));  // get keys
        if(is_array($keys)){ // if keys is array 
            foreach($keys as $v){  // loop array
                $max_array[]=$array[$v];  // set values to max_array
                unset($array[$v]);  // unset the keys to get next max value 
            }
        }else{ // if not array
            $max_array[]=$array[$keys]; // set values to max_array
            unset($array[$keys]); // unset the keys to get next max value
        }

    }
    return $max_array;
}
$g = getMaxValue($a,3);

Out Put:

Array
(
    [0] => 20
    [1] => 15
    [2] => 15
    [3] => 10
    [4] => 10
)

You can modify it to add conditions.

I thought of a couple of other possibilities.

First one:

  1. Find the lowest of the top three values

    $min = array_slice(array_unique($a, SORT_NUMERIC), -3)[0];
    
  2. Filter out any lower values

    $top3 = array_filter($a, function($x) use ($min) { return $x >= $min; });
    
  3. Sort the result

    sort($top3);
    

Advantages: less code
Disadvantages: less inefficient (sorts, iterates the entire array, sorts the result)

Second one:

  1. Sort the array in reverse order

    rsort($a);
    
  2. Iterate the array, appending items to your result array until you've appended three distinct items.

    $n = 0;
    $prev = null;
    $top = [];
    
    foreach ($a as $x) {
        if ($x != $prev) $n++;
        if ($n > 3) break;
        $top[] = $x;
        $prev = $x;
    }
    

Advantages: more efficient (sorts only once, iterates only as much as necessary)
Disadvantages: more code

This gives the results in descending order. You can optionally use array_unshift($top, $x) instead of $top[] = $x; to get it in ascending order, but I think I've read that array_unshift is less efficient because it reindexes the array after each addition, so if optimization is important it would probably be better to just use $top[] = $x; and then iterate the result in reverse order.