Home > Mobile >  Struggling with multi-dimensional array
Struggling with multi-dimensional array

Time:04-28

I'm feeling especially dumb and incompetent with PHP today so am seeking advice. I simply cannot work out the logic to extract the needed info from my multi-dimensional array. I'm hoping someone smart and kind can help me past my mental block here!

I have a multi-dimensional array of aroma observations that looks like this:

$aroma_observations = array(
[0] => Array ( [sample] => 9043 [aroma] => NUT [intensity] => 1 ) 
[1] => Array ( [sample] => 9043 [aroma] => NUT [intensity] => 2 ) 
[2] => Array ( [sample] => 9043 [aroma] => SPICE [intensity] => 2 ) 
[3] => Array ( [sample] => 9043 [aroma] => SPICE [intensity] => 2 ) 
[4] => Array ( [sample] => 9043 [aroma] => SPICE [intensity] => 1 ) 
[5] => Array ( [sample] => 9043 [aroma] => PEPPER [intensity] => 1 ) 
[6] => Array ( [sample] => 9043 [aroma] => PEPPER [intensity] => 1 ) 
[7] => Array ( [sample] => 9043 [aroma] => PEPPER [intensity] => 2 ) 
[8] => Array ( [sample] => 9043 [aroma] => WOOD [intensity] => 2 ) 
[9] => Array ( [sample] => 9043 [aroma] => WOOD [intensity] => 2 ) 
[10] => Array ( [sample] => 9043 [aroma] => WOOD [intensity] => 2 ) 
[11] => Array ( [sample] => 4585 [aroma] => SPICE [intensity] => 1 ) 
[12] => Array ( [sample] => 4585 [aroma] => SPICE [intensity] => 2 ) 
[13] => Array ( [sample] => 4585 [aroma] => HERB [intensity] => 1 ) 
[14] => Array ( [sample] => 4585 [aroma] => HERB [intensity] => 2 ) 
[15] => Array ( [sample] => 4585 [aroma] => WOOD [intensity] => 2 ) 
[16] => Array ( [sample] => 4585 [aroma] => WOOD [intensity] => 2 ) 
[17] => Array ( [sample] => 4585 [aroma] => WOOD [intensity] => 2 ) 
[18] => Array ( [sample] => 2466 [aroma] => SPICE [intensity] => 1 ) 
[19] => Array ( [sample] => 2466 [aroma] => SPICE [intensity] => 2 ) 
[20] => Array ( [sample] => 2466 [aroma] => SWEET [intensity] => 1 ) 
[21] => Array ( [sample] => 2466 [aroma] => SWEET [intensity] => 1 ) 
[22] => Array ( [sample] => 2466 [aroma] => SWEET [intensity] => 2 ) 
[23] => Array ( [sample] => 2466 [aroma] => WOOD [intensity] => 2 ) 
[24] => Array ( [sample] => 2466 [aroma] => WOOD [intensity] => 3 ) )

I need to create an array that reduces this down to the maximum intensity per aroma, per sample - like this:

$aroma_max_intensities = array ( 
[0] => Array ( [sample] => 9043 [aroma] => NUT [intensity] => 2 ) 
[1] => Array ( [sample] => 9043 [aroma] => SPICE [intensity] => 2 ) 
[2] => Array ( [sample] => 9043 [aroma] => PEPPER [intensity] => 2 ) 
[3] => Array ( [sample] => 9043 [aroma] => WOOD [intensity] => 2 ) 
[4] => Array ( [sample] => 4585 [aroma] => SPICE [intensity] => 2 ) 
[5] => Array ( [sample] => 4585 [aroma] => HERB [intensity] => 2 ) 
[6] => Array ( [sample] => 4585 [aroma] => WOOD [intensity] => 2 ) 
[7] => Array ( [sample] => 2466 [aroma] => SPICE [intensity] => 2 ) 
[8] => Array ( [sample] => 2466 [aroma] => SWEET [intensity] => 2 ) 
[9] => Array ( [sample] => 2466 [aroma] => WOOD [intensity] => 3 ) )

I keep going around & around on the best way to code this and am getting nowhere, so any advice is greatly appreciated.

DW

CodePudding user response:

You can use array_reduce to loop through the items and then check the intensity for that particular sample/aroma and increase the intensity if it's higher.

$results = array_values(array_reduce($aroma_observations, function($acc, $item) {
    if (!isset($acc[$item['sample'].$item['aroma']])) {
        $acc[$item['sample'].$item['aroma']] = $item;
    }
    if ((int)$item['intensity'] > $acc[$item['sample'].$item['aroma']]['intensity']) {
       $acc[$item['sample'].$item['aroma']]['intensity'] = (int)$item['intensity'];
    }
    return $acc;
}, []));

CodePudding user response:

Technically this isn't a multi-dimensional array but an array of associative-arrays which could be "seen as" an array of objects where each object has the following structure:

[
  "sample" => ...,
  "aroma" => ...,
  "intensity" => ...,
]

So you can approach this problem as you would approach a single dimensional array and then do something with each entry's value. Where each entry will be an "object" as described above.

Now, the expected result will also be an array of those "objects" but having only the ones with the highest intensity so what you want to do is basically filtering the original array.

For every problem there's always multiple possible solution but here's what I'd do:

I would keep an index with pointers to the entry in $aroma_observations having the highest intensity for every given combination of (sample, aroma).

So this index would look something like this:

[
  "sampleA.aromaA" => x,
  "sampleA.aromaB" => y,
  ...
]

Where x, y... are indexes in $aroma_observations containing the so-far highest intensity.

$indexOfMax = [];
for ($i = 0; $i < count($aroma_observations); $i  ) {
    $entry = $aroma_observations[$i];
    $indexOfMaxKey = "{$entry['sample']}.{$entry['aroma']}";
    if (!isset($indexOfMax[$indexOfMaxKey])) {
        // If the combination sample.aroma hasn't been indexed,
        // then add it now
        $indexOfMax[$indexOfMaxKey] = $i;
    } else {
        // The combination sample.aroma is in the index
        // Now, we compare the indexed intensity with the
        // current entry's intensity and update the index
        // if this new entry has a higher intensity
        
        // Take the pointer to the indexed aroma observation
        $indexedMax = $indexOfMax[$indexOfMaxKey];
        // Take the intensity corresponding to the indexed aroma observation
        $indexedIntensity = $aroma_observations[$indexedMax]['intensity'];

        if ($entry['intensity'] > $indexedIntensity) {
            $indexOfMax[$indexOfMaxKey] = $i;
        }
    }
}

echo '<pre>' . print_r($indexOfMax, true) . '</pre>';

Then, with the $indexOfMax fully populated, I'd build the results array:

$result = [];
foreach ($indexOfMax as $key => $indexOfValue) {
    $parts = explode('.', $key);
    $sample = $parts[0];
    $aroma = $parts[1];
    $intensity = $aroma_observations[$indexOfValue]['intensity'];
    $result[] = [
        'sample' => $sample,
        'aroma' => $aroma,
        'intensity' => $intensity,
    ];
}

echo '<pre>' . print_r($result, true) . '</pre>';

CodePudding user response:

try this code using sample and aroma key of array

<?PHP
echo "<pre>";
$final_array = [];

foreach($aroma_observations as $arr){
  $final_array[$arr['sample'].'-'.$arr['aroma']]['sample'] = $arr['sample'];
  $final_array[$arr['sample'].'-'.$arr['aroma']]['aroma'] = $arr['aroma'];
  $final_array[$arr['sample'].'-'.$arr['aroma']]['intensity'] = (isset($final_array[$arr['sample']-$arr['aroma']]['intensity'])) ? $final_array[$arr['sample']-$arr['aroma']]['intensity']   $arr['intensity'] : $arr['intensity'];    
}

$final_array = array_values($final_array);

print_r($final_array);
?>
  • Related