Khrisna Gunanasurya
Khrisna Gunanasurya

Reputation: 745

How to group a consecutive month in array using PHP?

I have this raw data of array

['jan', 'feb', 'mar', 'may', 'june', 'dec']

and I want to convert it to an array group like this

[
    0 => ['jan', 'feb', 'mar'],
    1 => ['may', 'june'],
    2 => ['dec'],
]

so what I wanted is to group a consecutive month from a dynamic return of months that coming from a checkboxes

and here is what I tried to do so far, been stuck with this problem for a while now

if (count($trip_months) == 12):
    $trip_months = 'ALL YEAR';
elseif (count($trip_months) > 0):
    $temp_text = '';
    $first_month = '';
    $last_month = '';
    $previous_month = '';
    $next_month = '';
    $separator = '';
    $months = ['jan' => '', 'feb' => '', 'mar' => '', 'apr' => '', 'may' => '', 'june' => '', 'july' => '', 'aug' => '', 'sept' => '', 'oct' => '', 'nov' => '', 'dec' => ''];

    foreach ($trip_months as $trip_month):
        if ($trip_month != 'jan') $previous_month = $months[$trip_month];
        if ($trip_month != 'dec') $next_month = $months[$trip_month];

        if ($first_month == '') {
            $first_month = $trip_month;
            $last_month = $trip_month;
        } else {

        }
    endforeach;
    $trip_months = $temp_text;
endif;

and I think i didn't go anywhere near with what I tried to achieve

Upvotes: 2

Views: 186

Answers (4)

freeek
freeek

Reputation: 978

You can make it even more optimal:

$input = ['jan', 'feb', 'mar', 'may', 'june', 'dec'];
$all = ['jan', 'feb', 'mar', 'apr', 'may', 'june', 'july', 'aug', 'sep', 'oct', 'nov', 'dec'];
$result = [];

$i = 0;
foreach($all as $month) {
    if(in_array($month, $input)) {
        $result[$i][] = $month;
        continue;
    }
    $i++;
}

var_dump($result);

Upvotes: 1

Claudio
Claudio

Reputation: 5203

Another solution:

$months = ['jan', 'feb', 'mar', 'may', 'june', 'dec'];

/* In case you need to sort
uasort($months, function($prev, $next) {
    return DateTime::createFromFormat('M', $prev) <=> DateTime::createFromFormat('M', $next);
});
*/

$groupedMonths = [];
$index = 0;

if (!empty($months[0])) {
    $groupedMonths[$index][] = $months[0];
}

for ($i = 1; $i < count($months); $i++) {
    $previous = DateTime::createFromFormat('M', $months[$i - 1]);
    $current = DateTime::createFromFormat('M', $months[$i]);

    $index += ((int) $current->format('n') - (int) $previous->format('n')) > 1 ? 1 : 0;
    $groupedMonths[$index][] = $months[$i];
}

Upvotes: 1

Nick
Nick

Reputation: 147166

Here's one way to do what you want. It uses a DateTime object to convert the month name to a number, then checks to see if the current month is consecutive with the last one, and if it is, adds it to the current trip, otherwise it starts a new trip:

$arr = ['jan', 'feb', 'mar', 'may', 'june', 'dec'];

$trip_months = array();
$last_month = -1;
$i = -1;
foreach ($arr as $month) {
    $this_month = DateTime::createFromFormat('M', $month)->format('n');
    if ($this_month != ($last_month + 1) % 12) {
        // new trip
        $trip_months[++$i] = array($month);
    }
    else {
        // continuing old trip
        $trip_months[$i][] = $month;
    }
    $last_month = $this_month;
}
print_r($trip_months);

Output:

Array
(
    [0] => Array
        (
            [0] => jan
            [1] => feb
            [2] => mar
        )    
    [1] => Array
        (
            [0] => may
            [1] => june
        )    
    [2] => Array
        (
            [0] => dec
        )    
)

Demo on 3v4l.org

Upvotes: 4

bars
bars

Reputation: 117

$a = ['jan', 'feb', 'mar', 'may', 'june', 'dec'];
$b = ['jan', 'feb', 'mar', 'apr', 'may', 'june', 'jule', 'aug', 'sep', 'oct', 'nov', 'dec'];
$c = [];

$i = 0;
$re = false;
foreach($b as $m) {
    if(in_array($m, $a)) {
        $c[$i][] = $m;
        $re = true;
    } elseif($re) {
        $i++;
        $re = false;
    }
}

var_dump($c);

Upvotes: 3

Related Questions