Search code examples
phparraysdata-structuresmappingmany-to-many

Create inverted map of many-to-many data within a multidimensional array


I am trying to create a new associative array where categories contain multiple items. My input array has the opposite orientation where individual items refer to multiple categories.

Input:

$items = [
    ["itemName" => "Hat", "price" => 10.99, "categories" => ["apparel", "head"]],
    ["itemName" => "Scarf", "price" => 7.99, "categories" => ["apparel", "neck"]],
    ["itemName" => "Watch", "price" => 19.99, "categories" => ["jewelry", "electronics"]],
    ["itemName" => "Necklace", "price" => 99.99, "categories" => ["jewelry", "neck"]],
    ["itemName" => "Headphones", "price" => 29.99, "categories" => ["head", "electronics"]]
];

Desired result:

[
  'apparel' => ['Hat', 'Scarf'],
  'head' => ['Hat', 'Headphones'],
  'neck' => ['Scarf', 'Necklace'],
  'jewelry' => ['Watch', 'Necklace'],
  'electronics' => ['Watch', 'Headphones']
]

My code:

include_once("./array.php");
    
$categories = [];
$categoryMap=array();
#map to find with the category as the key then the item as the value 
foreach ($items as $key => $value) {
    # code...
    $currentCategories = $value['categories'];
    for ($i = 0; $i < sizeof($currentCategories); $i++) {
        # code...
        // if not in keys for the categoryMap then initialize with the key with a value of an empty array
        // otherwise just add the the array of values using that keys
        
        // visual of how it should be 
        // [
        //     'buger':['bun','tomato','sauce']

        // ]
        
        array_push($categories, $currentCategories[$i]);
    }
}
$categories = array_unique($categories);

Solution

  • One way to produce the output would be to grab all categories, flatten it into a single array then remove dupes, loop over it and then use in_array to match the itemName for the key if the category exists in categories.

    <?php
    $items = array(
        array("itemName" => "Hat", "price" => 10.99, "categories" => ["apparel", "head"]),
        array("itemName" => "Scarf", "price" => 7.99, "categories" => ["apparel", "neck"]),
        array("itemName" => "Watch", "price" => 19.99, "categories" => ["jewelry", "electronics"]),
        array("itemName" => "Necklace", "price" => 99.99, "categories" => ["jewelry", "neck"]),
        array("itemName" => "Headphones", "price" => 29.99, "categories" => ["head", "electronics"])
    );
    
    
    foreach (array_unique(array_merge(...array_values(array_column($items, 'categories')))) as $value) {
       foreach ($items as $item) {
          if (in_array($value, $item['categories'])) {
              $categories[$value][] = $item['itemName'];
          } 
       }
    }
    
    print_r($categories);
    

    Result: (Online example)

    Array
    (
        [apparel] => Array
            (
                [0] => Hat
                [1] => Scarf
            )
    
        [head] => Array
            (
                [0] => Hat
                [1] => Headphones
            )
    
        [neck] => Array
            (
                [0] => Scarf
                [1] => Necklace
            )
    
        [jewelry] => Array
            (
                [0] => Watch
                [1] => Necklace
            )
    
        [electronics] => Array
            (
                [0] => Watch
                [1] => Headphones
            )
    
    )