php – Find max and min key in associative array-ThrowExceptions

Exception or error:

I have associative array like

array
{
    [company 1]=>array
                      (
                        [1981] => 1
                        [1945] => 3
                      )
   [company 2]=>array
                    (
                       [1990] => 18
                       [2005] => 13
                    )
   [company 3]=>array
                    (
                       [1950] => 6
                       [2012] => 9
                    )
}

I want to get lowest and highest key i.e. 1945 and 2012.
How can i achieve this? I have already searched over stackoverflow and Hightest value of an associative array is the nearest possibility but it gives out min and max value and I want min and max key.

**I don’t want to use foreach loop **

How to solve:

If you really hate foreach, here’s a solution:

$arr = array(
  "Company 1" => array(
    "1981" => 1,
    "1945" => 3
  ),

  "Company 2" => array(
    "1990" => 18,
    "2005" => 13
  ),

  "Company 3" => array(
    "1950" => 6,
    "2012" => 9
  )
);


$arr = array_map("array_keys", $arr);
$arr = array_reduce($arr, "array_merge", array());

Your $arr would end up like this:

Array
(
    [0] => 1981
    [1] => 1945
    [2] => 1990
    [3] => 2005
    [4] => 1950
    [5] => 2012
)

Now you can use min() and max() functions or sort() it get the highest and lowest value easily.

sort($arr);
echo end($arr); /*highest value; actual output: 2012*/
echo reset($arr); /*lowest value; actual output: 1945*/

Answer:

Try this one:
using foreach.

        $array = array("company 1" => array(1981 => 1, 1945 =>3),
                        "company 2" => array(1990 => 18, 2005 => 13),
                        "company 3" => array(1950 => 6, 2012 =>9),
        );

        $keys = array();
        foreach($array as $arr)
        {
            foreach( array_keys($arr) as $val)
            {
                array_push($keys, $val);
            }
        }
        sort($keys);
        $min = $keys[0];
        $max = $keys[count($keys)-1];

Without foreach:

        global $keys;
        $GLOBALS['keys'] = array();
        function sortme($arr)
        {
            is_array($arr)? array_map("sortme",array_keys($arr)): array_push($GLOBALS['keys'], $arr);

        }
        array_map("sortme",$array);
        sort($GLOBALS['keys']);
        $min = $GLOBALS['keys'][0];
        $max = $GLOBALS['keys'][count($GLOBALS['keys'])-1];
        echo "min = ".$min . "<br/>max = ".$max;

Answer:

ksort($array);
$min = reset($array);
end($array);
$max = key($array);

EDIT:
This works for simple array. You have 2 level structure, so it would be close to impossible to avoid looping through it.

However, if you have so many entries that even foreach is too slow, probably you should rethink your approach. For example, put this list into database and use SQL to do heavy lifting for you.

How exactly? Setup instance of MySQL or PostgreSQL (I personally prefer Postgres for many reasons), create database, create table with structure like this:

CREATE TABLE mytable (
    mytable_id INTEGER PRIMARY KEY,
    company VARCHAR(16),
    year INTEGER,
    value INTEGER,
    -- put some more metadata...
)

Technically, you should normalize your database and create separate tables for every object (like table for companies, for customers, orders, etc…), but you can come to this later.

Create indexes on columns you are going to be searching on (like year, company, etc):

CREATE INDEX mytable_year_idx ON mytable (year);
...

Finally, in your PHP script, connect to database and query it for what you wanted, something like this:

SELECT min(year) AS min_year,
       max(year) AS max_year
FROM mytable

Answer:

Because your input array is “very large” and “consumes [a] lot of time“, that is precisely a justification for using a set of simple language constructs to iterate the dataset in a single pass.

Using multiple array functions may look more concise or clever, but they will be making multiple passes over the data and invariably draw more resources than absolutely necessary.

Because your data is dealing with years, you can build business logic into the code logic with “magic numbers” — assuming that you will never encounter a negative year or a year from 10,000 and beyond.

If you want a more business-agnostic approach, you can seed the default min and max values by shifting the first row off the input array and fetching that subarray’s min and max keys.

Magic Number Code: (Demo)

$minYear = 9999;
$maxYear = 0;
foreach ($array as $row) {
    foreach ($row as $year => $value) {
        if ($year > $maxYear) {
            $maxYear = $year;
        }
        if ($year < $minYear) {
            $minYear = $year;
        }
    }
}
echo "MinYear = $minYear, MaxYear = $maxYear";
// MinYear = 1945, MaxYear = 2012

Shifted Defaults Code: (Demo)

if ($array) {
    $firstKeys = array_keys(array_shift($array));
    $minYear = min($firstKeys);
    $maxYear = max($firstKeys);
} else {
    $minYear = null;
    $maxYear = null;
}
foreach ($array as $row) {
    foreach ($row as $year => $value) {
        if ($year > $maxYear) {
            $maxYear = $year;
        } elseif ($year < $minYear) {
            $minYear = $year;
        }
    }
}
echo "MinYear = $minYear, MaxYear = $maxYear";

Notice that the Shifted snippet specifically handles the first dataset to get the defaults – which takes a few extra lines – but enjoys higher potential efficiency due to the elseif.

Neither of these techniques use iterated function calls, so they are virtually assured to perform faster than functional techniques.

Leave a Reply

Your email address will not be published. Required fields are marked *