S S
S S

Reputation: 1503

Group an array based on common value

I have an array with common product code & product name. For each product_code can have two types of cha_sty_id i.e push or pull. This is an array structure I have.

$array = [
            0 => [
                "product_code" => "67021687",
                "product_name" => "Spaces",
                "cha_sty_id" => "PUSH",
                "chs_name" => "WF"
            ],
            1 => [
                "product_code" => "67021687",
                "product_name" => "Spaces",
                "cha_sty_id" => "PUSH",
                "chs_name" => "WFR"
            ],
            2 => [
                "product_code" => "67021687",
                "product_name" => "Spaces",
                "cha_sty_id" => "PUSH",
                "chs_name" => "STK Food"
            ],
            3 => [
                "product_code" => "67021687",
                "product_name" => "Spaces",
                "cha_sty_id" => "PULL",
                "chs_name" => "4 Stars"
            ],
            4 => [
                "product_code" => "67021687",
                "product_name" => "Spaces",
                "cha_sty_id" => "PULL",
                "chs_name" => "5 Stars"
            ],
            5 => [
                "product_code" => "67021687",
                "product_name" => "Spaces",
                "cha_sty_id" => "PULL",
                "chs_name" => "Modern Thai"
            ],
            6 => [
                "product_code" => "67021687",
                "product_name" => "Spaces",
                "cha_sty_id" => "PULL",
                "chs_name" => "BBQ Buffet"
            ],
            7 => [
                "product_code" => "67021687",
                "product_name" => "Spaces",
                "cha_sty_id" => "PULL",
                "chs_name" => "Chinese"
            ]
        ];

Now I want result something like:

0 => [
    'product_code' => 67021687,
    'product_name' => 'Spaces.
    'push => array(....ALL chs_name for push),
    'pull' => array with chs_name for pull
]

I have tried some code

        $list = array();
        foreach ($records as $data) {
            $list[$data['product_code']][] = $data;
            if($data['cha_sty_id'] == 'PUSH') {
                $list[$data['product_code']]['push'] = $data['chs_name'];
            } else {
                $list[$data['product_code']]['pull'] = $data['chs_name'];
            }
        }

But I could not solve it. Can anybody pls help me.

Thank You.

Upvotes: 0

Views: 86

Answers (3)

mickmackusa
mickmackusa

Reputation: 47894

There is no need for any conditional expressions while partially pivoting your data into groups. Use the product_code values as temporary first level keys and use the cha_sty_id values as dynamic second level keys. Re-index the result array after the loop finishes with array_values().

One approach uses a body-less foreach as explained here.

Code: (Demo)

$result = [];
foreach (
    $array
    as
    [
        'product_code' => $productCode,
        'cha_sty_id' => $id,
        'product_code' => $result[$code]['product_code'],
        'product_name' => $result[$code]['product_name'],
        'chs_name' => $result[$code][strtolower($id)][]
    ]
);
var_export(array_values($result));

A more traditional style is to group and pivot inside the body of the loop.

Code: (Demo)

$result = [];
foreach ($array as $row) {
    $result[$row['product_code']]['product_code'] = $row['product_code'];
    $result[$row['product_code']]['product_name'] = $row['product_name'];
    $result[$row['product_code']][strtolower($row['cha_sty_id'])][] = $row['chs_name'];
}
var_export(array_values($result));

Due to the fact that the group logic is possibly going to return an array size that differs from the input array, array_reduce() is the most appropriate functional iterator for this task.

Code: (Demo)

var_export(
    array_values(
        array_reduce(
            $array,
            function($result, $row) {
                $result[$row['product_code']]['product_code'] = $row['product_code'];
                $result[$row['product_code']]['product_name'] = $row['product_name'];
                $result[$row['product_code']][strtolower($row['cha_sty_id'])][] = $row['chs_name'];
                return $result;
            },
            []
        )
    )
);

All techniques above produce the exact same result.

Upvotes: 0

Rakesh Jakhar
Rakesh Jakhar

Reputation: 6388

You can use array_walk,array_push

$res = [];
array_walk($array, function($v, $k) use (&$res){ 
if(in_array($v['product_code'], array_column($res, 'product_code'))){
    array_push($res[$v['product_code']]["push"], $v['chs_name']);
    array_push($res[$v['product_code']]["pull"], $v['chs_name']);
}else{
  $res[$v['product_code']] = [
      "product_code" => $v['product_code'],
      "product_name" => $v['product_name'],
      "push" => [$v['chs_name']],
      "pull" => [$v['chs_name']]
  ];
 }
});
echo '<pre>';
print_r(array_values($res));

DEMO HERE

Upvotes: 1

dWinder
dWinder

Reputation: 11642

How about this modify your foreach loop to this:

$list = array();
foreach ($records as $data) {
    $code = $data['product_code']; // as key
    if (!isset($list[$code])) { // set new array if not exist
        $list[$code] = array("product_code" => $code, "product_name" => $data['product_name'], "push" => [], "pull" => []);
    }
    $subKey = strtolower($data['cha_sty_id']); // get push / pull as new subkey
    $list[$code][$subKey][] = $data['chs_name']; // append to the array
}

You can use array_values to remove the code keys from $list after the loop if not needed

Upvotes: 1

Related Questions