Extracting min and max number for each month from 2d array

Hello,

I have an array and i need to export min and max number for each month/year:

$results = array();
$results[] = array('created_month' => '1-2019', 'min' => 2.3, 'max' => -0.2);
$results[] = array('created_month' => '1-2019', 'min' => 1.3, 'max' => 0.3);
$results[] = array('created_month' => '1-2019', 'min' => -1.3,'max' => 1.2);
$results[] = array('created_month' => '1-2019', 'min' => 0.3, 'max' => 0.2);

$results[] = array('created_month' => '2-2019', 'min' => 1.0, 'max' => 3.1);
$results[] = array('created_month' => '2-2019', 'min' => 0.4, 'max' => 2.3);
$results[] = array('created_month' => '2-2019', 'min' => 2.0, 'max' => 1.1);

$results[] = array('created_month' => '3-2019', 'min' => -1.4,'max' => 3);
$results[] = array('created_month' => '3-2019', 'min' => 2.3, 'max' => 1.5);

so output need to look like this

Array
(
    [0] => Array
        (
            [created_month] => 1-2019
            [min] => -1.3
            [max] => 1.2
        )

    [1] => Array
        (
            [created_month] => 2-2019
            [min] => 0.4
            [max] => 3.1
        )

)

but problem is that i am not getting results for 3-2019
here is code:

// extract single month, 'created_month' like 1-2019, 2-2019, 3-2019
$single_month = array();
for ($i=0; $i < count($results); $i++) {
	if (!in_array($results[$i]['created_month'], $single_month))
		array_push($single_month, $results[$i]['created_month']);
}

// get min and max value for each month
$min = array();
$max = array();
$final = array();
for ($i=0; $i < count($single_month); $i++) { 
	for ($j=0; $j < count($results); $j++) { 
		if ($results[$j]['created_month'] == $single_month[$i]) {
			if (!in_array($results[$j]['min'], $min))
				array_push($min, $results[$j]['min']);
			if (!in_array($results[$j]['max'], $max))
				array_push($max, $results[$j]['max']);
		} else {
			// take only min and max from each month/year
			if (count($min) >= 1 || count($max) >= 1) {
				array_push($final, array(
					'created_month' => $single_month[$i],
					'min' => min($min),
					'max' => max($max)
				));
			}
			$min = []; // reset array
			$max = []; // reset array
		}
	}
}

echo '<br>----------------- $single_month extracted to array ----------------- <br>';
echo '<pre>';
print_r($single_month);
echo '</pre>';

echo '<br>----------------- $final array need to return min and max value for each month  ----------------- <br>';
echo '<pre>';
print_r($final);
echo '</pre>';

Some things that might help you/streamline your effort:
array_filter
array_column
array_unique

this looks like results from a database, if so, why not using the aggregation functions there? (GROUP BY, MIN, MAX)

Otherwise i would use array_map or array_reduce.

thanks for this but i never worked with those array functions, this doesn’t solve my problem i have now

yes they are from database but problem is that i switched from mysql to mssql and they are not working in same way with grouping and min, max and mssql i didn’t find solution that can give me same results as mysql, so i must use this to solve that.

This still leave a question what is problem with code i use and why it doesn’t show me last month ? Where did i made mistake ?

Edit:
First loop to give me only months replaced with

$array_months = array_unique(array_column($results, 'created_month'));

Good start.

Why doesnt your code give you a result for month 3? Well simply put - when does your code tell it to write to $final? Why does that logic not work for the LAST month? (For that matter, why does that logic not work if the entries aren’t gathered up in month-order?)

Challenge: You can simplify your code a lot by eliminating the J loop altogether, and use a combination of array_filter and array_column to find your max and min values. The logic goes like this:

For a given value of 'month':
  Get the subset of entries that match that month.
  The min of that subset is the min of the "min" column.
  The max of that subset is the max of the "max" column.

Ok here is my final code that works

// extract single month, 'created_month' like 1-2019, 2-2019, 3-2019
$single_month = array_values(array_unique(array_column($results, 'created_month')));

// get min and max value for each month
$final = array();
$temp = array();

for ($i=0; $i < count($single_month); $i++) {
	// month/year like 1-2019, 2-2019, 3-2019
	$month = $single_month[$i];

	//
	$temp = array_filter($results, function($var) use ($month) {
		return ($var['created_month'] == $month);
	});

	//
	if (!in_array($month, $final))
		array_push($final, array(
			'created_month' => $month,
			'min' => min(array_column($temp, 'min')),
			'max' => max(array_column($temp, 'max'))
		));
}

and output

Array
(
    [0] => Array
        (
            [created_month] => 1-2019
            [min] => -1.3
            [max] => 1.2
        )

    [1] => Array
        (
            [created_month] => 2-2019
            [min] => 0.4
            [max] => 3.1
        )

    [2] => Array
        (
            [created_month] => 3-2019
            [min] => -1.4
            [max] => 3
        )

)
1 Like

Great that you worked out the problems. Just as an addition, you can create the output array much more simply, without all of those array functions.

<?php

$results = array();
$results[] = array('created_month' => '1-2019', 'min' => 2.3, 'max' => -0.2);
$results[] = array('created_month' => '1-2019', 'min' => 1.3, 'max' => 0.3);
$results[] = array('created_month' => '1-2019', 'min' => -1.3,'max' => 1.2);
$results[] = array('created_month' => '1-2019', 'min' => 0.3, 'max' => 0.2);
$results[] = array('created_month' => '2-2019', 'min' => 1.0, 'max' => 3.1);
$results[] = array('created_month' => '2-2019', 'min' => 0.4, 'max' => 2.3);
$results[] = array('created_month' => '2-2019', 'min' => 2.0, 'max' => 1.1);
$results[] = array('created_month' => '3-2019', 'min' => -1.4,'max' => 3);
$results[] = array('created_month' => '3-2019', 'min' => 2.3, 'max' => 1.5);

$output = array();
foreach ($results as $result) {
    $month = $result['created_month'];
    if (!isset($output[$month])) {
        $output[$month] = $result;
    } else {
        $output[$month]['min'] = min($output[$month]['min'], $result['min']);
        $output[$month]['max'] = max($output[$month]['max'], $result['max']);
    }
}
print_r($output);

This will give an output array with the three sub-arrays that you want, one per month. It works by looping over the original results array, and building up the output array with the new min and max values for the given month each time.

(Aside: the above will have the keys of the output array be the months, if you want 0, 1, 2 instead then you can use the array_values() function after the loop.)

1 Like