Home > Software engineering >  split an array evenly depend on the number of the giving years
split an array evenly depend on the number of the giving years

Time:11-16

I have an array contain a list of courses

$courses = ['php', 'mysql', 'java', 'ruby'];

I have also a function that helps me to split this array into pieces, depends on the number of the giving years.

this is my function:

public function planner($courses, $periodicity, $preserve_keys = null)
{
    $nbr = (int) ceil(count($courses) / $periodicity);

    if($nbr > 0){
       return array_chunk($courses, $nbr, $preserve_keys);
    }
    return $courses;
}

The output is fine if I pass the number 1 or 2 or 4 in the $periodicity parameter I'm having the bug only when I pass number 3 as $periodicity, with 4 courses in my array

I get:

[
  [
    'php',
    'mysql'
  ],
  [
    'java',
    'ruby'
  ]
]

as you can see I'm getting 2 courses each year, since I passed 3 as periodicity.

The expected result in that case should be:

[
  [
    'php'
  ],
  [
    'mysql'
  ],
  [
    'java',
    'ruby'
  ]
]
  • 1 Course for the first year
  • 1 course for the second year
  • 2 courses for the last year

CodePudding user response:

This solves it slightly differently.
First is to split up the even segments, this is the first set of elements which are split with the same amount of elements(so the first 2 items in your example). Also note that instead of using ceil(), I use floor() to round down the value.

Then the remaining elements are added in one chunk to the end of the array.

function planner($courses, $periodicity, $preserve_keys = false)
{
    $nbrDays = (int) floor(count($courses) / $periodicity);

    if ($nbrDays > 0) {
        $initialSplit = array_slice($courses, 0, $nbrDays * ($periodicity - 1), $preserve_keys);
        $split = array_chunk($initialSplit, $nbrDays, $preserve_keys);
        // Add in the remaining elements
        $split[] = array_slice($courses, $nbrDays * ($periodicity - 1), null, $preserve_keys);
        return $split;
    }
    return $courses;
}

CodePudding user response:

You can very easily spread with modulus. But the complicated thing is to put the remaining at bottom.

$planner = function (array $plans, int $periods): array {
    $result = [];
    $i      = 0;
    $remain = count($plans) % $periods;
    $last   = count($plans) - $remain;
    while ($plan = current($plans)) {
        if ($last === $i) break;
        $result[$i   % $periods][] = $plan;
        next($plans);
    }
    while ($remain-- > 0) {
        $result[$i - 1][] = current($plans);
        next($plans);
    }
    return $result;
};

echo json_encode($planner(['php', 'mysql', 'java', 'ruby'], 1)), "\n";
echo json_encode($planner(['php', 'mysql', 'java', 'ruby'], 2)), "\n";
echo json_encode($planner(['php', 'mysql', 'java', 'ruby'], 3)), "\n";
echo json_encode($planner(['php', 'mysql', 'java', 'ruby'], 4)), "\n";

Output

[["php","mysql","java","ruby"]]
[["php","java"],["mysql","ruby"]]
[["php"],["mysql"],["java","ruby"]]
[["php"],["mysql"],["java"],["ruby"]]

Alternative version with different result

Here a simpler version, if you don't need the rest have in the bottom.

$planner = function (array $plans, int $periods): array {
    $result = [];
    $i      = 0;
    foreach ($plans as $plan) {
        $result[$i   % $periods][] = $plan;
    }
    return $result;
};

echo json_encode($planner(['php', 'mysql', 'java', 'ruby'], 1)), "\n";
echo json_encode($planner(['php', 'mysql', 'java', 'ruby'], 2)), "\n";
echo json_encode($planner(['php', 'mysql', 'java', 'ruby'], 3)), "\n";
echo json_encode($planner(['php', 'mysql', 'java', 'ruby'], 4)), "\n";

Output

[["php","mysql","java","ruby"]]
[["php","java"],["mysql","ruby"]]
[["php","ruby"],["mysql"],["java"]]
[["php"],["mysql"],["java"],["ruby"]]

CodePudding user response:

you can't use array_chunk() for this, since it only uses ints for length. you will have to devise your own array splitting algorithm, or use the one in this answer:

Split array into a specific number of chunks

  •  Tags:  
  • php
  • Related