Transform multiple values to single key

Viewed 41

I am using php 7.1 and I have the following array:

<?php

$arr = array (
    0 =>
        array (
            'Product' => 'Product1',
            'Exact_Match_Keyword' => 'apples freshness',
        ),
    1 =>
        array (
            'Product' => 'Product1',
            'Exact_Match_Keyword' => 'apples',
        ),
    2 =>
        array (
            'Product' => 'Product1',
            'Exact_Match_Keyword' => 'oranges',
        ),
    3 =>
        array (
            'Product' => 'Product2',
            'Exact_Match_Keyword' => 'apples freshness',
        ),
    4 =>
        array (
            'Product' => 'Product2',
            'Exact_Match_Keyword' => 'apples',
        ),
);

$arr = array_merge_recursive($arr);
var_dump($arr);

/* WANTED DATA STRUCTURE

$arr = array (
    0 =>
        array (
            'Product' => 'Product1',
            'Exact_Match_Keyword' => array('apples freshness', 'apples', 'oranges'),
        ),
    1 =>
        array (
            'Product' => 'Product2',
            'Exact_Match_Keyword' => array('apples freshness', 'apples'),
        ),
);
*/

I tried to use array_merge_recursive however this does not give me my wanted data structure.

Any suggestions what I am doing wrong?

I appreciate your replies!

3 Answers

You can use array_reduce to handle simple logic like this for you. The example below will provide you with the expected format you've posted.

$example = array_values(
    array_reduce(
        $arr,
        static function ($acc, $row) {
            if (!isset($acc[$row['Product']])) {
                $acc[$row['Product']] = [
                    'Product' => $row['Product'],
                    'Exact_Match_Keyword' => [$row['Exact_Match_Keyword']],
                ];
            } else {
                $acc[$row['Product']]['Exact_Match_Keyword'] = array_merge(
                    $acc[$row['Product']]['Exact_Match_Keyword'],
                    [$row['Exact_Match_Keyword']]
                );
            }
            return $acc;
        }
    ));
print_r($example);

It can be simplified further if the format you expect is flexible:

$example = array_reduce(
    $arr,
    static function ($acc, $row) {
        if (!isset($acc[$row['Product']])) {
            $acc[$row['Product']] = [$row['Exact_Match_Keyword']];
        } else {
            $acc[$row['Product']] = array_merge(
                $acc[$row['Product']],
                [$row['Exact_Match_Keyword']]
            );
        }
        return $acc;
    }
);
print_r($example);
//Output: 
//[
//    'Product1'=> ['apples freshness', 'apples', 'oranges'],
//    'Product2'=> ['apples freshness', 'apples']
//]

I think this gets you what you want. Probably not the most graceful thing in the world but it's roughly the logic you'd want to follow.

  $temp = [];
  foreach ($arr as $v)
  {
    $pname = $v['Product'];
    if (!isset($temp[$pname]))
    {
      $temp[$pname] = []; 
    } 
    $temp[$pname][] = $v['Exact_Match_Keyword'];
  }

  $out = [];
  foreach ($temp as $k => $v)
  {
    $out[] = [
      'Product' => $k,
      'Exact_Match_Name' => $v
    ];
  }

php > var_dump($out);
php shell code:1:
array(2) {
  [0] =>
  array(2) {
    'Product' =>
    string(8) "Product1"
    'Exact_Match_Name' =>
    array(3) {
      [0] =>
      string(16) "apples freshness"
      [1] =>
      string(6) "apples"
      [2] =>
      string(7) "oranges"
    }
  }
  [1] =>
  array(2) {
    'Product' =>
    string(8) "Product2"
    'Exact_Match_Name' =>
    array(2) {
      [0] =>
      string(16) "apples freshness"
      [1] =>
      string(6) "apples"
    }
  }
}

For future reference, if you would like to use the array_merge_recursive() approach on its own, the input data might have to be a little different from what I can tell.

After looking at the example in the documentation page for array_merge_recursive(), I wonder if the original input data needs to be structured a little differently. I think there needs to be matching inner array keys in order for the final array to have something to combine on for the various inner keys. In the example data below, I used the Products key to combine on for the first inner key.

I don't know if it's possible for your starting data to be structured differently for this process, but if the data could look like the following (based on the example on the documentation page for array_merge_recursive()):

<?php

$ar1 = array(
    "Products" => array(
        "Product1" => array(
            "Exact_Match_Keyword" => array('apples freshness')
        )
    )
);
$ar2 = array(
    "Products" => array(
        "Product1" => array(
            "Exact_Match_Keyword" => array('apples')
        )
    )
);
$ar3 = array(
    "Products" => array(
        "Product1" => array(
            "Exact_Match_Keyword" => array('oranges')
        )
    )
);

$ar4 = array(
    "Products" => array(
        "Product2" => array(
            "Exact_Match_Keyword" => array('apples freshness')
        )
    )
);
$ar5 = array(
    "Products" => array(
        "Product2" => array(
            "Exact_Match_Keyword" => array('apples')
        )
    )
);

$result = array_merge_recursive($ar1, $ar2, $ar3, $ar4, $ar5);
print_r($result);

The output should then look like this:

Array
(
    [Products] => Array
        (
            [Product1] => Array
                (
                    [Exact_Match_Keyword] => Array
                        (
                            [0] => apples freshness
                            [1] => apples
                            [2] => oranges
                        )

                )

            [Product2] => Array
                (
                    [Exact_Match_Keyword] => Array
                        (
                            [0] => apples freshness
                            [1] => apples
                        )

                )

        )

)
Related