简体   繁体   中英

Add grouping elements to 2d array and sum values in respective group

I need to add new elemets to my array when a new category value is encountered. When a category value is encountered after the first time, its value1 and value2 values should be added to the first encounter's respective values.

Also, in the result array, I no longer wish to keep the category column. The category-grouping rows should use the category value as its name value.

Sample input:

$datas = [
    [
        'category' => 'Solution',
        'name' => 'Name1',
        'value1' => 20,
        'value2' => 21
    ],
    [
        'category' => 'Solution',
        'name' => 'Name2',
        'value1' => 30,
        'value2' => 31
    ],
    [
        'category' => 'Solution1',
        'name' => 'Name3',
        'value1' => 40,
        'value2' => 41
    ]
];

Desired result:

[
    ['name' => 'Solution',  'value1' => 50, 'value2' => 52],
    ['name' => 'Name1',     'value1' => 20, 'value2' => 21],
    ['name' => 'Name2',     'value1' => 30, 'value2' => 31],
    ['name' => 'Solution1', 'value1' => 40, 'value2' => 41],
    ['name' => 'Name3',     'value1' => 40, 'value2' => 41]
]

I tried like this:

private function groupByProductSuperCategory($datas)
{
    $return = [];
    foreach ($datas as $data) {
        $return[$data['category']][$data['name']] = array_sum(array_column('category', $data);
    }
    return $return;
}

The idea is to calculate first all sum values for by category, and after that just put values from name like another array. Have you an idea of how to do that?

From the posted array... To end in the desired array, there is some tiny fixes to do first. But I assumed it was due to typos while copying here...

So here is the array I started with:

$result = [
  0 => [
    "category"   => 'Solution',
    "name"       => 'Name1',
    "value1"     => 20,
    "value2"     => 21
  ],
  1 => [
    "category"   => 'Solution',
    "name"       => 'Name2',
    "value1"     => 30,
    "value2"     => 31
  ],
  2 => [
    "category"   => 'Solution1',
    "name"       => 'Name3',
    "value1"     => 40,
    "value2"     => 41
  ]
];

Now, that re-organization of the data is a bit more complex than it looks... You need to perform several loops to:

  • Find distinct "category" names
  • Perform the summations for each
  • Add the sum item and the single items

So here is the code I ended with:

function groupByProductSuperCategory($datas){
  $category = [];
  $return = [];

  // Find distinct categories
  foreach ($datas as $data) {
    if(!in_array($data["category"],$category)){
      array_push($category,$data["category"]);
    }
  }

  // For each distinct category, add the sum item and the single items
  foreach ($category as $cat) {

    // Get the sums
    if(!in_array($cat,$return)){

      $sum1 = 0;
      $sum2 = 0;
      foreach ($datas as $data) {
        if($data["category"] == $cat){
          $sum1 += $data["value1"];
          $sum2 += $data["value2"];
        }
      }
    }

    // Push the sums in the return array
    array_push($return,[
      "name" => $cat,
      "value1" => $sum1,
      "value2" => $sum2,
    ]);

    // Push the single elements
    foreach ($datas as $data) {
      if($cat == $data["category"]){
        array_push($return,[
          "name" => $data["name"],
          "value1" => $data["value1"],
          "value2" => $data["value2"],
        ]);
      }
    }


  }

  return $return;

}

Here is a PHPFiddle to try it out... Hit [F9] to run.

It is much more direct, efficient, and readable to implement a single loop and push reference variables into the result array to allow summing based on shared categories without keeping track of the actual indexes of the category rows.

Code: ( Demo )

$result = [];
foreach ($array as $row) {
    if (!isset($ref[$row['category']])) {
        $ref[$row['category']] = [
            'name' => $row['category'],
            'value1' => 0,
            'value2' => 0
        ];
        $result[] = &$ref[$row['category']];
    }
    $ref[$row['category']]['value1'] += $row['value1'];
    $ref[$row['category']]['value2'] += $row['value2'];
    unset($row['category']);
    $result[] = $row;
}
var_export($result);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM