Ahmed Fouad
Ahmed Fouad

Reputation: 3073

Flip associative array and store new values in subarrays to prevent losing duplicated values

I have a flat associative array which may contain duplicate values.

Array (
    [for-juniors] => product_category 
    [for-men] => product_category
    [coats] => product_category
    [for-women] => product_category
    [7-diamonds] => brand
) 

I need to restructure the data to store the original values as new keys and the original keys pushed into subarrays associated with the new keys.

array(
    'product_category' => array(
        'for-juniors',
        'for-men',
        'coats',
        'for-women'
    ),
    'brand' => array(
        '7-diamonds'
    )
);

Upvotes: 4

Views: 1644

Answers (3)

mickmackusa
mickmackusa

Reputation: 47991

Because within a foreach() loop, the values are declared BEFORE the keys, you can actually populate the new data structure with a body-less foreach() loop.

Code: (Demo)

$array = [
    'for-juniors' => 'product_category',
    'for-men' => 'product_category',
    'coats' => 'product_category',
    'for-women' => 'product_category',
    '7-diamonds' => 'brand'
];

$grouped = [];
foreach ($array as $grouped[$group][] => $group);
var_export($grouped);

Output:

array (
  'product_category' => 
  array (
    0 => 'for-juniors',
    1 => 'for-men',
    2 => 'coats',
    3 => 'for-women',
  ),
  'brand' => 
  array (
    0 => '7-diamonds',
  ),
)

Upvotes: 1

s3c
s3c

Reputation: 1851

This'll do:

function array_flip_safe(array $array) : array
{
    return array_reduce(array_keys($array), function ($carry, $key) use (&$array) {
        $carry[$array[$key]] ??= []; // PHP 7.0 - ^7.3: $carry[$array[$key]] = $carry[$array[$key]] ?? [];
        $carry[$array[$key]][] = $key;
        return $carry;
    }, []);
}

The callback creates an empty array if the array doesn't already exist. Then it appends current iteration's $key ($value of array_keys($array)) to that array.

Here's an example for better understanding:

$businessHours = [
    'mo' => '13:00 - 16:00',
    'tu' => '8:00 - 12:00',
    'we' => '13:00 - 16:00',
    'th' => '8:00 - 12:00',
    'fr' => '13:00 - 16:00',
    'sa' => '',
    'su' => '',
];

$flipped = array_flip_safe($businessHours);

ray($flipped); (or var_dump, var_export, etc.) outputs:

array:3 [▼
  "13:00 - 16:00" => array:3 [▼
    0 => "mo"
    1 => "we"
    2 => "fr"
  ]
  "8:00 - 12:00" => array:2 [▼
    0 => "tu"
    1 => "th"
  ]
  "" => array:2 [▼
    0 => "sa"
    1 => "su"
  ]
]

Note that the order of inner arrays' values is the same as the order of original array's keys.

Upvotes: 0

deceze
deceze

Reputation: 522451

$grouped = array();
foreach ($input as $choice => $group) {
    $grouped[$group][] = $choice;
}

var_dump($grouped);

Upvotes: 6

Related Questions