Search code examples
phpmultidimensional-arraygroupingarray-column

Transform values in an array to another multidimensional array


Currently, this is my code, but it doesn't work:

//$queryBalance is the array received from an sql select
foreach ($queryBalance as $index => $runrows){ 
    $val = $runrows->balance;
    $val = str_ireplace(".","",$val);
    $val = str_ireplace(",",".",$val);
    //echo($i.' - '.$runrows->id_month.' ; ');
    //$valor = $runrows->id_month == $i ? $val : 'Null';
    if($i > $monthFim){
        $i = $monthInicio-1;
        array_push($balanceArray, $balanceTeste);                     
        echo('('.$i.' - '.$runrows->id_month.'); ');
        //dd('('.$balanceArray.' - '.$balanceTeste.'); ');
    }else{
        array_push($balanceTeste, $valor);
    }
    $i++; 
}

I want to transform this input array ($queryBalance):

array:6 [
   0 => {
    "balance": "-257,21"
    "id_month": 1
    "year": "2018"
  }
  1 => {
    "balance": "-257,21"
    "id_month": 2
    "year": "2018"
  }
  2 => {
    "balance": "0"
    "id_month": 1
    "year": "2018"
  }
  3 => {
    "balance": "0"
    "id_month": 2
    "year": "2018"
  }
  4 => {
    "balance": "-64609,14"
    "id_month": 1
    "year": "2018"
  }
  5 => {
    "balance": "-64609,14"
    "id_month": 2
    "year": "2018"
  }
]

into this (the indexes name is irrelevant, I put it there to exemplify the logic):

array:3 [
   0 => {
    "balance_month1_year2018": "-257,21"
    "balance_month2_year2018": "-257,21"
  }
  1 => {
    "balance_month1_year2018": "0"
    "balance_month2_year2018": "0"
  }
  2 => {
    "balance_month1_year2018": "-64609,14"
    "balance_month2_year2018": "-64609,14"
  }
]

Basically, I want group by year and month to get the balances.

ps: The data will always be ordered


Solution

    1. Generate an array of unique year and month combinations.
      (*Declare as keys to ensure that they are unique).

    2. Iterate $queryBalance until is empty/exhausted.
      (*If you need to re-use the original $queryBalance make a copy.)

    3. Assign the first subarray of $queryBalance as a variable for the next line.

    4. If expected date pair from $uniques is same as $first date pair, remove the first subarray (via array_shift()) and store the balance; otherwise store NULL and do not modify $queryBalance.

    5. $temp is a "batching" array. When the foreach loop is finished, the batch is ready to transfer to $result.

    Code: (Demo)

    $queryBalance=[
        (object)["balance"=>"-257,21","id_month"=>12,"year"=>"2017"],
        (object)["balance"=>"-257,21","id_month"=>1,"year"=>"2018"],
        (object)["balance"=>"-257,21","id_month"=>2,"year"=>"2018"],
        (object)["balance"=>"166,66","id_month"=>3,"year"=>"2018"],
        (object)["balance"=>"55","id_month"=>12,"year"=>"2017"],
        //(object)["balance"=>"0","id_month"=>1,"year"=>"2018"],
        (object)["balance"=>"0","id_month"=>2,"year"=>"2018"],
        (object)["balance"=>"55","id_month"=>3,"year"=>"2018"],
        (object)["balance"=>"-22257,21","id_month"=>12,"year"=>"2017"],
        (object)["balance"=>"-64609,14","id_month"=>1,"year"=>"2018"],
        (object)["balance"=>"-64609,14","id_month"=>2,"year"=>"2018"],
        (object)["balance"=>"-12234,89","id_month"=>3,"year"=>"2018"]
    ];
    foreach($queryBalance as $row){
        $uniques[$row->year.'-'.$row->id_month]=NULL;  // determine all unique date groups
    }
    
    while($queryBalance){
        $temp=[];
        foreach($uniques as $date=>$null){
            $first=current($queryBalance);  // cache the element that is currently first in $queryBalance
            $temp[]=($date==$first->year.'-'.$first->id_month) ? array_shift($queryBalance)->balance : NULL;  // extract from array, or store NULL without modifying $queryBalance
        }
        $result[]=$temp;
    }
    
    var_export($result);
    

    Output:

    array (
      0 => 
      array (
        0 => '-257,21',
        1 => '-257,21',
        2 => '-257,21',
        3 => '166,66',
      ),
      1 => 
      array (
        0 => '55',
        1 => NULL,
        2 => '0',
        3 => '55',
      ),
      2 => 
      array (
        0 => '-22257,21',
        1 => '-64609,14',
        2 => '-64609,14',
        3 => '-12234,89',
      ),
    )