PHP多维数组合并键并添加一个值

My array is like this :

array(  
    (int) 0 => array(
    'projet_id' => '1',
    'activite_id' => '1',
    'domaine_id' => null,
    'aretirer' => (float) 4
),  
(int) 1 => array(
        'projet_id' => '1',
        'activite_id' => '3',
        'domaine_id' => null,
        'aretirer' => (float) 1
    ),  
(int) 2 => array(
        'projet_id' => '1',
        'activite_id' => '1',
        'domaine_id' => null,
        'aretirer' => (float) 2
    ),  
(int) 3 => array(
        'projet_id' => '1',
        'activite_id' => '3',
        'domaine_id' => null,
        'aretirer' => (float) 2
    )
)

I want to sum the aretirer key where projet_id,activite_id and domaine_id are the same

I tried with foreach but i haven't got the good result like this

array(  
(int) 0 => array(
        'projet_id' => '1',
        'activite_id' => '1',
        'domaine_id' => null,
        'aretirer' => (float) 6
    ),  
(int) 1 => array(
        'projet_id' => '1',
        'activite_id' => '3',
        'domaine_id' => null,
        'aretirer' => (float) 3
    )
)

thats what i tried to do

public function array_sum($array){
    $arrayfusion=array();
    $i=0;
    foreach($array as $item):
        $arrayfusion[$i]['projet_id']=$item['projet_id'];
        $arrayfusion[$i]['activite_id']=$item['activite_id'];
        $arrayfusion[$i]['domaine_id']=$item['domaine_id'];   
        $arrayfusion[$i]['aretirer']=$item['aretirer']; 
        foreach($array as $itemnext):
            if($itemnext['projet_id']==$item['projet_id'] && $itemnext['activite_id']==$item['activite_id'] && $itemnext['domaine_id']==$item['domaine_id']):
                $arrayfusion[$i]['aretirer']+=$itemnext['aretirer']; 
            endif;
        endforeach;
        $i++;
    endforeach;
    return $arrayfusion;
}

thank's for your help

$array = array(  
    array(
        'projet_id' => '1',
        'activite_id' => '1',
        'domaine_id' => null,
        'aretirer' =>  4
    ),  
    array(
        'projet_id' => '1',
        'activite_id' => '3',
        'domaine_id' => null,
        'aretirer' =>  1
    ),  
    array(
        'projet_id' => '1',
        'activite_id' => '1',
        'domaine_id' => null,
        'aretirer' => 2
    ),  
    array(
        'projet_id' => '1',
        'activite_id' => '3',
        'domaine_id' => null,
        'aretirer' => 2
    )
);

$sortedArray = array();
$assignedValues = array();

foreach ($array as $arrayItem)
{
    $ukey = $arrayItem['projet_id'].'-'.$arrayItem['activite_id'].'-'.$arrayItem['domaine_id'];


    if (!isset($sortedArray[$ukey]))
    {
        $sortedArray[$ukey] = array();
    }

    $sortedArray[$ukey][] = $arrayItem['aretirer'];

    if (!isset($assignedValues[$ukey]))
    {
        $assignedValues[$ukey] = array(
            'projet_id' => $arrayItem['projet_id'],
            'activite_id' => $arrayItem['activite_id'],
            'domaine_id' => $arrayItem['domaine_id']
        );
    }
}

foreach ($sortedArray as $ukey => $arrayItem)
{
    $sum = array_sum($arrayItem);

    var_dump($assignedValues[$ukey]);
    var_dump('SUM: ' . $sum);
}

UPDATE: added separator

In your answer you're checking for $item['flag'] but not setting it. So first you need to set it inside the inner loop. But to do that you need to be able to modify the array elements, if you just do:

foreach($array as $itemnext):
  if($itemnext['projet_id']==$item['projet_id'] && $itemnext['activite_id']==$item['activite_id'] && $itemnext['domaine_id']==$item['domaine_id']):
    $arrayfusion[$i]['aretirer']+=$itemnext['aretirer']; 
    $itemnext['flag'] = true;
  endif;
endforeach;

It will not work, as the inner code has a copy of $itemnext, rather than the original. So you either need to set it directly in the array like this:

foreach($array as $key => $itemnext):
  if($itemnext['projet_id']==$item['projet_id'] && $itemnext['activite_id']==$item['activite_id'] && $itemnext['domaine_id']==$item['domaine_id']):
    $arrayfusion[$i]['aretirer']+=$itemnext['aretirer']; 
    $array["$key"]['flag'] = true;
  endif;
endforeach;

or pass the array element in by reference so you can modify it by starting the foreach like this:

foreach($array as &$itemnext):

This will still get the wrong answer as you could the first item in any matching set twice. You could either set flag on the outer element as well or just initialize ['aretirer'] to zero since you're going to add all the values back on anyway.

You could also replace the flag check with:

  if(!isset($item['flag'])):

otherwise it'll complain about ['flag'] not being set (if you have that warning enabled).

However, that solution goes round the entire array once for each array element -- that's going to be slow for a big array. A better idea would be to extract the data into a better multi-dimensional array:

foreach ($myArray as $data) { 
  if (!isset($newArray[$data['projet_id']][$data['activite_id']][$data['domaine_id']])) { 
    $newArray[$data['projet_id']][$data['activite_id']][$data['domaine_id']] = 0;
  };
  $newArray[$data['projet_id']][$data['activite_id']][$data['domaine_id']] += $data['aretirer'];  
}

Which might be enough, depending what you do with the data, otherwise you could take that data and build the original array format back:

foreach($newArray as $projet_id => $act_domArray) { 
  foreach($act_domArray as $activite_id => $domArray) { 
    foreach($domArray as $domaine_id => $aretirer) { 
      $finalArray[] = array('projet_id' => $projet_id, 'activite_id' => $activite_id, 
                            'domaine_id' => $domaine_id, 'aretirer' => $aretirer);
    }
  }
}

Or, you create an object for the data and define a comparison method in that object. Then use that to collapse the array.

If it was up to me to develop this logic, I'd place this logic inside of a function. Honestly, I would probably go one step further and build it into a class (especially if you are using PHP >= 5.1). Though that is outside of the scope you are asking for, it may be worth checking out http://php.net/manual/en/language.oop5.php for additional information on Object-Oriented Programming practices.

However, to satisfy your immediate question relating to a proper foreach statement that will perform aggregate functions based on a unique index (projet_id, activite_id, and domaine_id) - I would refer to the following:

$arrDataSetList = array(  
    0 => array(
        'projet_id' => '1',
        'activite_id' => '1',
        'domaine_id' => null,
        'aretirer' => (float) 4
    ),  
    1 => array(
            'projet_id' => '1',
            'activite_id' => '3',
            'domaine_id' => null,
            'aretirer' => (float) 1
        ),  
    2 => array(
            'projet_id' => '1',
            'activite_id' => '1',
            'domaine_id' => null,
            'aretirer' => (float) 2
        ),  
    3 => array(
            'projet_id' => '1',
            'activite_id' => '3',
            'domaine_id' => null,
            'aretirer' => (float) 2
        )
);

$arrAggregateDataSet = array();
$arrAggregateKeys = array('project_id','activite_id','domaine_id'); // Sets up the keys to define that to group your dataset with
foreach ($arrDataSetList as $arrDataSetListItem) {
    // STEP 1: Defining the aggregate key
    $arrKeyValues = array(); // Key values to join later
    foreach ($arrAggregateKeys as $strKey) {
        if (array_key_exists($strKey, $arrDataSetListItem) && !empty($arrDataSetListItem[$strKey]){
            $arrKeyValues[] = $arrDataSetListItem[$strKey];
        }
        else {
            $arrKeyValues[] = ''; // Empty if null
    }

    $strKey = join('-',$arrKeyValues);  // Your Unique Key for this Data Set List Item

    // STEP 2: If the unique key does not yet exist - initialize the aggregated dataset
    if (!array_key_exists($strKey, $arrAggregateDataSet)) {
        $arrAggregateDataSet[$strKey] = $arrDataSetListItem;
    }
    // STEP 3: If the unique key DOES exist, perform the aggregate functions necessary
    else {
        $arrAggregateDataSet[$strKey]['aretirer'] += $arrDataSetListItem['aretirer'];
    }
}

The output will look like the following to you use the var_dump() function on $arrAggregateDataSet:

array(2) {
  ["1-1-"]=>
  array(4) {
    ["projet_id"]=>
    string(1) "1"
    ["activite_id"]=>
    string(1) "1"
    ["domaine_id"]=>
    NULL
    ["aretirer"]=>
    float(6)
  }
  ["1-3-"]=>
  array(4) {
    ["projet_id"]=>
    string(1) "1"
    ["activite_id"]=>
    string(1) "3"
    ["domaine_id"]=>
    NULL
    ["aretirer"]=>
    float(3)
  }
}

This is expected to work in all flavors of PHP 4 (>= 4.0.7) and 5.