Home > OS >  Group array row on one column and form subarrays of varying depth/structure
Group array row on one column and form subarrays of varying depth/structure

Time:08-18

I want to group rows in an array with the same color and then similar size data into special subarrays.

Sample array:

$array = [
    ['color'=>'#000000','size'=>'L','count'=>2],
    ['color'=>'#000000','size'=>'XL','count'=>1],
    ['color'=>'#ffffff','size'=>'L','count'=>2],
    ['color'=>'#ffffff','size'=>'XL','count'=>1],
    ['color'=>'#ff0000','size'=>'L','count'=>1]
];

And I want them to be like this JSON:

[{
   "color": "#000000",
   "size": [
      {
       "value": "L","count": 2
      },
      {
        "value": "Xl","count": 1
      }
    ]
  },
  {
    "color": "#ffffff",
    "size": [
      {
        "value": "L","count": 2
      },
      {
        "value": "Xl","count": 1
      }
    ]
  },
  {
    "color": "#ff0000",
    "size": "L",
    "count": 1
  }
]

CodePudding user response:

UPDATE: Added a correction for the desired output at the bottom.

This seems easy, but is rather difficult to do right. The best approach is to divide and conquer. First collect the data together, which belongs together, and then make the nice JSON output. My first step is therefore this:

$input = [['color'=>'#000000','size'=>'L','count'=>2],
          ['color'=>'#000000','size'=>'XL','count'=>1],
          ['color'=>'#ffffff','size'=>'L','count'=>2],
          ['color'=>'#ffffff','size'=>'XL','count'=>1],
          ['color'=>'#ff0000','size'=>'L','count'=>1]];
          
$colors = [];

foreach ($input as $product) {
    extract($product);
    $colors[$color][$size] = $count;
}

echo json_encode($colors,  JSON_PRETTY_PRINT);

This outputs:

Array
(
    [#000000] => Array
        (
            [L] => 2
            [XL] => 1
        )

    [#ffffff] => Array
        (
            [L] => 2
            [XL] => 1
        )

    [#ff0000] => Array
        (
            [L] => 1
        )

)

Please note that extract() should be used with care, since it can generate more variables than you bargained for, but it is very useful here. Never use it at the global scope, like I did here.

And now we turn this into the wanted JSON, like this:

$output = [];

foreach ($colors as $color => $sizes) {
    $data = [];
    foreach ($sizes as $size => $count) {
        $data[] = ['value' => $size,
                   'count' => $count];
    }
    $output[] = ['color' => $color,
                 'size'  => $data];
}
          
echo json_encode($output,  JSON_PRETTY_PRINT);

This outputs:

[
    {
        "color": "#000000",
        "size": [
            {
                "value": "L",
                "count": 2
            },
            {
                "value": "XL",
                "count": 1
            }
        ]
    },
    {
        "color": "#ffffff",
        "size": [
            {
                "value": "L",
                "count": 2
            },
            {
                "value": "XL",
                "count": 1
            }
        ]
    },
    {
        "color": "#ff0000",
        "size": [
            {
                "value": "L",
                "count": 1
            }
        ]
    }
]

You might want to put all this code inside a function.

Here's a PHPFiddle.

NOTE: It is important to note that this code assumes that there are no duplicate color/size combinations in the input array.

In case the output you want wasn't a result of a typo, here's how you can modify the second loop to get it:

$output = [];

foreach ($colors as $color => $sizes) {
    $data = [];
    foreach ($sizes as $size => $count) {
        $data[] = ['value' => $size,
                   'count' => $count];
    }
    if (count($data) == 1) {
        $output[] = ['color' => $color,
                     'size'  => $data[0]['value'],
                     'count' => $data[0]['count']];
    } else {
        $output[] = ['color' => $color,
                     'size'  => $data];
    }                     
}
          
echo json_encode($output,  JSON_PRETTY_PRINT);

See this PHPFiddle

CodePudding user response:

Iterate your array and establish associative fiest level keys based on the color values.

There are three conditional ways that each row's data must be stored to give your exact desired result. There is no need to employ more than one loop.

  1. When a color has never been encountered before, save the unchanged row with the new first level key.

  2. On the second encounter of a given color, the structure must be adjusted to allow deeper subarrays.

  3. After a given color has been encountered two or more times, the two values in the row can be pushed directly into the deeper subarray (size).

Code: (Demo) (with extract())

$result = [];
foreach ($array as $row) {
    if (!isset($result[$row['color']])) {
        $result[$row['color']] = $row;
    } elseif (isset($result[$row['color']]['count'])) {
        $result[$row['color']]['size'] = [
            [
                'value' => $result[$row['color']]['size'],
                'count' => $result[$row['color']]['count']
            ],
            [
                'value' => $row['size'],
                'count' => $row['count']
            ]
        ];
        unset($result[$row['color']]['count']);
    } else {
        $result[$row['color']]['size'][] = [
            'value' => $row['size'],
            'count' => $row['count']
        ];
    }
}
echo json_encode(array_values($result), JSON_PRETTY_PRINT);

CodePudding user response:

Loop through the array and create a new array with a condition that meets it like this

foreach( $mixed_colors as $color ) 
{
    if($color->color == $color1) 
             { 

             $color1[] = array(
                 
                'color' => $color->color,
                'size' => $color->size,
                'count' => $color->count

                
                );
                
               
             }
                
    }

Then you put the arrays into another multi dimensional array.So the you will have arrays for all the colors, then you will put them into one array to have all the specific color arrays.

  • Related