asprin
asprin

Reputation: 9833

Efficient way to compare associative array values without using foreach

For an array such as:

$array = array(
    735 => array('name'=>'Alpha', 'num'=>1),
    584 => array('name'=>'Beta', 'num'=>4),
    857 => array('name'=>'Gamma', 'num'=>1),
    982 => array('name'=>'Delta', 'num'=>2)
);

what would be the best way to filter elements with least value of num. That is, in this case, the solution would be the following array:

array(
    735 => array('name'=>'Alpha', 'num'=>1),
    857 => array('name'=>'Gamma', 'num'=>1)
);

I'm aware that this can be done via a foreach loop and keeping track of the least value but I was hoping there would be some array function which would do the job.

My current approach is:

$num_values = array();
foreach($array as $id => $meta)
{
    $num_values[] = $meta['num'];
}
$min_num_value = min($num_values);

$filtered_array = array();
foreach($array as $id => $meta)
{
    if($meta['num'] == $min_num_value)
    {
        $filtered_array[$id] = $meta;
    }
}
print_r($filtered_array);

which, as you can see, is clearly not the best way to go about the task.

Upvotes: 0

Views: 236

Answers (3)

lisachenko
lisachenko

Reputation: 6092

Optimized version of filtering with minimum value calculation and O(n) complexity.

$array = array(
    735 => array('name'=>'Alpha', 'num'=>1),
    584 => array('name'=>'Beta', 'num'=>4),
    857 => array('name'=>'Gamma', 'num'=>1),
    982 => array('name'=>'Delta', 'num'=>2)
);

$minValue      = PHP_INT_MAX;
$filteredArray = [];
foreach ($array as $key=>$data) {
    $itemNumber = $data['num'];
    if ($itemNumber < $minValue) {
        $filteredArray = [$key => $data];
        $minValue      = $itemNumber;
    } elseif ($itemNumber === $minValue) {
        $filteredArray[$key] = $data;
    }
}

var_dump($filteredArray);

Performance of foreach is better than any array_xxx() functions plus invocation of closures/functions. So, this solution must be efficient even for big arrays.

Upvotes: 3

Pankaj katiyar
Pankaj katiyar

Reputation: 464

this might be help you

$arr = array(
    735 => array('name'=>'Alpha', 'num'=>1),
    584 => array('name'=>'Beta', 'num'=>4),
    857 => array('name'=>'Gamma', 'num'=>1),
    982 => array('name'=>'Delta', 'num'=>2)
);

$inventory = array_map("array_values", $arr);
usort($inventory, function ($item1, $item2) {
    if ($item1[1] == $item2[1]) return 0;
    return $item1[1] < $item2[1] ? -1 : 1;
});

echo "<pre>";print_r($inventory);

Upvotes: 0

Suchit kumar
Suchit kumar

Reputation: 11859

Since min gives only one record you can try like this: It will remove first foreach loop, rest is yours.

$array = array(
        735 => array('name'=>'Alpha', 'num'=>1),
        584 => array('name'=>'Beta', 'num'=>4),
        857 => array('name'=>'Gamma', 'num'=>1),
        982 => array('name'=>'Delta', 'num'=>2)
);
$val = min($array);
$filtered_array=array();
foreach($array as $id => $meta)
{
    if($meta['num'] == $val['num'])
    {
        $filtered_array[$id] = $meta;
    }
}
print_r($filtered_array);

Upvotes: 0

Related Questions