Skip to content

Instantly share code, notes, and snippets.

@mcaskill
Last active October 25, 2023 17:38
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mcaskill/ef7484e316972bbb1a6903aab00495e2 to your computer and use it in GitHub Desktop.
Save mcaskill/ef7484e316972bbb1a6903aab00495e2 to your computer and use it in GitHub Desktop.
PHP : Splits an array into chunks using a callback function.

array_chunk_by

(PHP 5 >= 5.4)
array_chunk_by — Splits an array into chunks using a callback function.

Description

array array_chunk_by( array $array, mixed $key1 [, mixed $... ] )

Chunks an array into arrays by iteratively applying the $callback function to the elements of the $array.

Based on Raivo Laanemets' groupAdjacent() function.

Parameters

  • $array — The array to have chunking performed on.

  • $callback — The callback function to use.

    bool callback ( mixed $previous, mixed $current )
    • $previous - Holds the value of the previous iteration.
    • $current - Holds the value of the current iteration.

    If the $callback function returns TRUE, the the current value from $array is split into a new chunk.

  • $preserve_keys — When set to TRUE keys will be preserved. Default is FALSE which will reindex the chunk numerically.

Return Values

Returns a multidimensional numerically indexed array, starting with zero, with each dimension containing related elements.

Examples

Example #1 array_chunk_by()

Splits the array where the difference between adjacent elements is greater than 1.

$input  = [ 1, 2, 3, 4, 14, 21, 23, 28, 29 ];
$result = array_chunk_by( $input, function ($prev, $curr) {
  return ($curr - $prev) > 1;
});

var_export( $result );

The above example will output:

array (
  0 => 
  array (
    0 => 1,
    1 => 2,
    2 => 3,
    3 => 4,
  ),
  1 => 
  array (
    0 => 14,
  ),
  2 => 
  array (
    0 => 21,
  ),
  3 => 
  array (
    0 => 23,
  ),
  4 => 
  array (
    0 => 28,
    1 => 29,
  ),
)

Example #2 array_chunk_by()

Groups the array where adjacent elements share the same value.

$input  = [ 5, 5, 3, 5, 3, 3 ];
$result = array_chunk_by( $input, function ($prev, $curr) {
  return ($previous != $current);
});

var_export( $result );

The above example will output:

array (
  0 => 
  array (
    0 => 5,
    1 => 5,
  ),
  1 => 
  array (
    0 => 3,
  ),
  2 => 
  array (
    0 => 5,
  ),
  3 => 
  array (
    0 => 3,
    1 => 3,
  ),
)

Installation

With Composer

$ composer require mcaskill/php-array-chunk-by

Without Composer

Why are you not using Composer?

Download Function.Array-Group-By.php from the gist and save the file into your project path somewhere.

{
"name": "mcaskill/php-array-chunk-by",
"description": "Splits an array into chunks using a callback function.",
"license": "MIT",
"authors": [
{
"name": "Chauncey McAskill",
"email": "chauncey@mcaskill.ca",
"homepage": "https://github.com/mcaskill"
}
],
"keywords": [
"function"
],
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"require": {
"php": ">=5.4.0"
},
"autoload": {
"files": ["Function.Array-Chunk-By.php"]
}
}
<?php
if (!function_exists('array_chunk_by')) {
/**
* Splits an array into chunks using a callback function.
*
* Chunks an array into arrays by iteratively applying the $callback function
* to the elements of the $array.
*
* @see https://rlaanemets.com/post/show/group-array-by-adjacent-elements-in-javascript
*
* @param array $array The array to have chunking performed on.
* @param callable $callback {
* The callback function to use.
*
* ```
* bool callback ( mixed $previous, mixed $current )
* ```
*
* @param mixed $previous Holds the value of the previous iteration.
* @param mixed $current Holds the value of the current iteration.
* @return bool If TRUE, the the current value from $array is split
* into a new chunk.
* }
* @param bool $preserve_keys When set to TRUE keys will be preserved.
* Default is FALSE which will reindex the chunk numerically.
* @return array Returns a multidimensional numerically indexed array,
* starting with zero, with each dimension containing related elements.
*/
function array_chunk_by(array $array, callable $callback, bool $preserve_keys = false) : array
{
$reducer = function ( array $carry, $key ) use ( $array, $callback, $preserve_keys ) {
$current = $array[$key];
$length = count($carry);
if ( $length > 0 ) {
$chunk = &$carry[ $length - 1 ];
end($chunk);
$previous = $chunk[ key($chunk) ];
if ( $callback($previous, $current) ) {
// Split, create a new group.
if ($preserve_keys) {
$carry[] = [ $key => $current ];
} else {
$carry[] = [ $current ];
}
} else {
// Put into the $currentrent group.
if ($preserve_keys) {
$chunk[$key] = $current;
} else {
$chunk[] = $current;
}
}
} else {
// The first group.
if ($preserve_keys) {
$carry[] = [ $key => $current ];
} else {
$carry[] = [ $current ];
}
}
return $carry;
};
return array_reduce(array_keys($array), $reducer, []);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment