php - Get highest and lowest values from an array where order is like "AAA", "AA", "A", "BBB", "BB", etc

281

What I'm trying to do is creating a custom rating system like this:

AAA - Highest rating
AA
A
BBB
BB
B
CCC
CC
C - Lowest rating

In which AAA is the highest and C the lowest. For this this to work I need PHP to know which rating is the highest, lowest and everything in between and evaluate series of ratings based on that. I allready figured out how to create a sorting withusort() like so:

$ratings = array("a" => "AAA", "b" => "AA", "c" => "A", "d" => "BBB", "e" => "BB", "f" => "B", "g" => "CCC", "h" => "CC", "i" => "C");
$sortedRatings = usort($ratings, "cmp_function");

This will return an array neatly sorted from highest priority to lowest. Now I need to go ahead and use this sorting to get the highest and lowest rating from an array like this one:

$ratingHistory = array("BB", "B", "CCC", "C", "BB");

So how could I go about getting the highest and lowest value from$ratingHistory based on the sorting as in$sortedRatings ? I hope someone can help me out with this one. If my problem isn't completely clear to you, drop a comment so I can try to explain further.

Edit:

Just to be clear. The expected outcomes would be:

Highest: BB
Lowest: C
754

Answer

Solution:

This solution works with your original$ratings array and — throughusort() — sort$ratingHistory:

$ratings = array("a" => "AAA", "b" => "AA", "c" => "A", "d" => "BBB", "e" => "BB", "f" => "B", "g" => "CCC", "h" => "CC", "i" => "C");
$ratingHistory = array("BB", "B", "CCC", "C", "BB");

usort
(
    $ratingHistory,
    function( $a, $b ) use( $ratings )
    {
        return strcmp( array_search( $a, $ratings ), array_search( $b, $ratings ) );
    }
);

$result = array( 'max'=>current($ratingHistory), 'min'=>end($ratingHistory) );

print_r( $result );

Will print:

Array
(
    [max] => BB
    [min] => C
)

Performance:

I have compared the performance of above example with aforeach(), anarray_map() (all cases with both associative and enumerated array as$ratings and with different$ratingHistory sizes). Theusort() method is in anyhow far the more efficient. This because you have anyway to iterate complete array, but withusort you can use less commands/functions/comparisons.

326

Answer

Solution:

You can try this code :

$ratings = array("", "AAA","AA", "A", "BBB", "BB", "B", "CCC", "CC", "C");
$ratingHistory = array("BB", "B", "CCC", "C", "BB");

$min = 0;
$max = INF;
foreach ($ratingHistory as $row)
{
    $rate = array_search($row, $ratings);
    if ($rate && $rate > $min) {
        $min = $rate;
    }
    if ($rate && $rate < $max) {
        $max = $rate;
    }
}

echo 'Min : '. $ratings[$min];
echo '<br />Max : '. $ratings[$max];

If you test, the values are BB and C for your example.

734

Answer

Solution:

Because ALL of your encounterable values are in your ratings lookup array, you can enjoy the sweet brevity ofarray_intersect(). This will remove all values from the$ratings array which are not found in the$ratingsHistory array. Of course, the$ratings array is already in order, so the results are instantly accessible from the first and last elements.

Code: (Demo)

$ratingHistory = array_intersect($ratings, $ratingHistory);
var_export([
    'min' => $ratingHistory[key($ratingHistory)],
    'max' => $ratingHistory[array_key_last($ratingHistory)]
]);

If you don't want to maintain a lookup array (to allow your code to be more dynamic/robust and require less maintenance), spell out the logic. Using a linear foreach loop will have a smaller time complexity and will offer better performance than a non-linear sort likeusort().

Code: (Demo)

$result = ['min' => null, 'max' => null];
foreach ($array as $value) {
    if (
        !$result['min']
        || (!trim($value, $result['min']) ? $value < $result['min'] : $value > $result['min'])
    ) {
        $result['min'] = $value;
    }
    if (
        !$result['max']
        || (!trim($value, $result['max']) ? $value > $result['max'] : $value < $result['max'])
    ) {
        $result['max'] = $value;
    }
}
var_export($result);

Maintaining a lookup array for priorities and callingusort() is also a clean approach, but this has been asked before on Stack Overflow and it will have the poorest time complexity score of these three snippets. 1 2 3 4

Code: (Demo)

$lookup = array_flip($ratings);
usort($ratingHistory,  fn($a, $b) => $lookup[$a] <=> $lookup[$b]);
var_export([
    'min' => $ratingHistory[0],
    'max' => $ratingHistory[array_key_last($ratingHistory)]
]);

P.s. Any technique that is making iterated calls ofarray_search() will have worse performance than ALL of my snippets above. "Value searching" an array is always going to be slower than "key searching" an array in PHP.

People are also looking for solutions to the problem: batch file - Plink fails to run when executed from PHP in wamp, but works when executed manually

Source

Didn't find the answer?

Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.

Ask a Question

Write quick answer

Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.

Similar questions

Find the answer in similar questions on our website.