Opsional
Opsional

Reputation: 543

Group 2d array by column value and concatenate values within each group

I have a simple php array for location postcode and their name. I want compress 'code' by 'name'. This code from WooCommerce database zones.

$new_arr = [
    [
        'name' => 'Jambi Selatan',
        'code' => '36139',
        'code_name' => '36139 - Jambi Selatan'
    ],
    [
        'name' => 'Jambi Selatan',
        'code' => '36137',
        'code_name' => '36137 - Jambi Selatan'
    ],
    [
        'name' => 'Bagan Pete',
        'code' => '36129',
        'code_name' => '36129 - Bagan Pete'
    ],
    [
        'name' => 'Bagan Pete',
        'code' => '36127',
        'code_name' => '36127 - Bagan Pete'
    ]
];

I want get final result combined by 'name' and 'code' like this: i try array_unique method but not working.

Array (
    [0] => Array
        (
            [name] => Jambi Selatan
            [code] => 36139, 36137
            [code_name] => 36139, 36139 - Jambi Selatan
        )

    [1] => Array
        (
            [name] => Bagan Pete
            [code] => 36127, 36129
            [code_name] => 36127, 36129 - Bagan Pete
        )
)

I try this method, but not fix at 'code_name'

$out = array();
foreach ($new_arr as $key => $value){
    if (array_key_exists($value['name'], $out)){
        $out[$value['name']]['code'] .= ', '.$value['code'];
    } else {
        $out[$value['name']] = array(
            'name' => $value['name'],
            'code' => $value['code'],
            'code_name' => $value['code'] . ' - ' . $value['name']
        );
    }
}
$out = array_values($out);               

print_r($out);

Upvotes: 0

Views: 148

Answers (4)

mickmackusa
mickmackusa

Reputation: 47904

Definitely avoid any suggestions that use more than one loop to group and concatenate the data.

I do endorse @Opsional's snippet. An alternative approach is to push reference variables into the result array, then only concatenate comma-separated values to the appropriate reference variable.

Code: (Demo)

$result = [];
foreach ($arr as $row) {
    if (!isset($ref[$row['name']])) {
        $ref[$row['name']] = $row;
        $result[] = &$ref[$row['name']];
    } else {
        $ref[$row['name']]['code'] .= ', ' . $row['code'];
        $ref[$row['name']]['code_name'] .= ', ' . $row['code_name'];
    }
}
var_export($result);

For any purist developers that insist on destroying references, call unset($ref) after the loop.


Here is a streamlined version of @Opsional's snippet: (Demo)

$result = [];
foreach ($arr as $row) {
    if (!isset($result[$row['name']])) {
        $result[$row['name']] = $row;
    } else {
        $result[$row['name']]['code'] .= ', ' . $row['code'];
        $result[$row['name']]['code_name'] .= ', ' . $row['code_name'];
    }
}
var_export(array_values($result));

Upvotes: 0

Suman Singh
Suman Singh

Reputation: 1377

Please try below one as another approach:

<?php
$arr = Array (
    Array
        (
            'name' => 'Jambi Selatan',
            'code' => '36139',
            'code_name' => '36139 - Jambi Selatan'
        ),
    Array
        (
            'name' => 'Jambi Selatan',
            'code' => '36137',
            'code_name' => '36137 - Jambi Selatan'
        ),
    Array
        (
            'name' => 'Bagan Pete',
            'code' => '36129',
            'code_name' => '36129 - Bagan Pete'
        ),
    Array
        (
            'name' => 'Bagan Pete',
            'code' => '36127',
            'code_name' => '36127 - Bagan Pete'
        )
);

$newarr = array();
$finalArr = array();
foreach($arr as $aa) {
    $newarr[$aa['name']][] = $aa;
}

foreach($newarr as $kk => $bb) {
    foreach($bb as $cc) {
        $finalArr[$kk]['name'] = $cc['name'];

        if(isset($finalArr[$kk]['code'])) {
            $finalArr[$kk]['code'] = $finalArr[$kk]['code'].','.$cc['code'];
        } else {
            $finalArr[$kk]['code'] = $cc['code'];
        }
        if(isset($finalArr[$kk]['code_name'])) {
            $finalArr[$kk]['code_name'] = $finalArr[$kk]['code_name'].','.$cc['code_name'];
        } else {
            $finalArr[$kk]['code_name'] = $cc['code_name'];
        }
    }
}
echo "<pre>";
print_r($finalArr);
echo "</pre>";
?>

Upvotes: 0

Jack jdeoel
Jack jdeoel

Reputation: 4584

You have to check duplicate name by in_array and update exist array value .If not exist insert that value to $out array .

$out = array();
foreach($new_arr as $k=>$v) {
    //empty array state
    if(count($out) == 0) {
        $out[] = $v;
        continue;
    }   
    foreach ($out as $key => $value) {
        if(in_array($v["name"],$value)) {
            $out[$key]["code"] .= ",".$v["code"];
            //for the code_name output as OP described
            $nn = explode("-", $value["code_name"]);
            $l = count($nn) - 1;
            unset($nn[$l]);
            $out[$key]["code_name"] = implode($nn).",".$v["code_name"];
            break;
        } else {
            if((count($out)-1) == $key) {
                $out[] = $v;
            }
        }
    }
}
var_dump($out);

Upvotes: 1

Opsional
Opsional

Reputation: 543

For someone have problem like me, this method for fix it:

$out = array();
            foreach ($new_arr as $key => $value){
                if (array_key_exists($value['name'], $out)){
                    $out[$value['name']]['code'] .= ', '.$value['code'];
                    $out[$value['name']]['code_name'] .= ', '.$value['code'] . ' - ' . $value['name'];
                } else {
                    $out[$value['name']] = array(
                        'name' => $value['name'],
                        'code' => $value['code'],
                        'code_name' => $value['code']
                    );
                }
            }
            $out = array_values($out);
            print_r($out);

Final result;

Array
(
    [0] => Array
        (
            [name] => Jambi Selatan
            [code] => 36139, 36137
            [code_name] => 36139, 36137 - Jambi Selatan
        )

    [1] => Array
        (
            [name] => Bagan Pete
            [code] => 36129, 36127
            [code_name] => 36129, 36127 - Bagan Pete
        )

)

Upvotes: 0

Related Questions