Search code examples
phparraysconcatenationgroupingdelimited

Group 1d array of filenames by their leading text and join filenames in each group with a delimiter


I have a flat array containing filenames. I need to group the filenames by their leading substring and form pipe-delimited elements.

Sample input:

$j = [
    'ma_1_49812_5318.jpg',
    'ma_1_49812_5319.jpg',
    'ma_1_49813_5320.jpg',
    'ma_1_49813_5321.jpg',
];

Desired result:

[
    'ma_1_49812_5318.jpg|ma_1_49812_5319.jpg',
    'ma_1_49813_5320.jpg|ma_1_49813_5321.jpg',
]

My coding attempt:

$entry = array();
$lastjs = '';
$jx ='';
foreach ($j as $group) {
    $jx = explode("_", $group)[2];
    if ($jx == $lastjs || $lastjs == '') {
        $entry[] = $group;
        $lastjs = $jx;
    }
    else
    {
        $entry[] = $group;
        $lastjs = $jx;
    }
}

My incorrect result:

(
    [0] => ma_1_49812_5318.jpg
    [1] => ma_1_49812_5319.jpg
    [2] => ma_1_49813_5320.jpg
    [3] => ma_1_49813_5321.jpg
)

Solution

  • When you encounter a new real estate property, push a new reference into the result array. When you re-encounter a real estate property, concatenate the reference variable with a pipe then the new value. Using this technique, you do not need to use temporary keys in the result array (this also eliminates the need to call array_values() to re-indes the result array).

    Code: (Demo)

    $result = [];
    foreach ($j as $filename) {
        $groupBy = preg_replace('/_[^_]+$/', '', $filename); // remove unique filename ending
        if (!isset($ref[$groupBy])) {
            $ref[$groupBy] = $filename;
            $result[] = &$ref[$groupBy];
        } else {
            $ref[$groupBy] .= "|$filename";
        }
    }
    var_export($result);