-1

I have two multi-dimensional arrays - $taste_observations as the name suggests is a list of tastes recorded as our tasters test products. Each observation has the tester's name, the name of the taste (e.g. sweet, spicy etc) a "stage" when the observation was made and an intensity of the taste.

There are a finite number of tastes and I'm trying to summarize the observations into another array $taste_summary with one entry for each taste, capturing the name of the taste, the count of how many times it was observed, the maximum intensity and the sum of the intensities so I can calculate the avg intensity.

There's something wrong with my nested foreach loops though, as I always wind up with 0 for all accumulated values. Here's the code I'm using, with simplified sample data:

// Capture the list of taste observations across analyses and phases of analysis
            $taste_observations = array();
// Temporary test data for Stack Overflow Question
            $taste_observations[] = [
                'analyst' => 'Ken', 
                'phase' => 'Entrance', 
                'taste' => 'Sweet', 
                'intensity' => 1
            ];
            $taste_observations[] = [
                'analyst' => 'Ken', 
                'phase' => 'Entrance', 
                'taste' => 'Spicy', 
                'intensity' => 1
            ];
            $taste_observations[] = [
                'analyst' => 'Ken', 
                'phase' => 'Center', 
                'taste' => 'Sweet', 
                'intensity' => 2
            ];
            $taste_observations[] = [
                'analyst' => 'Bob', 
                'phase' => 'Entrance', 
                'taste' => 'Savory', 
                'intensity' => 1
            ];
            $taste_observations[] = [
                'analyst' => 'Bob', 
                'phase' => 'After', 
                'taste' => 'Sweet', 
            ];
            
// Sort the list of taste observations by taste ASC
            $keys = array_column($taste_observations, 'taste');
            array_multisort($keys, SORT_ASC, $taste_observations);

// Initialize the taste summary array
            $taste_summary = array(
                array(
                    'taste' => 'Savory',
                    'count' => 0,
                    'frequency' => 0,
                    'max' => 0,
                    'sum' => 0,
                ),
                array(
                    'taste' => 'Spicy',
                    'count' => 0,
                    'frequency' => 0,
                    'max' => 0,
                    'sum' => 0,
                ),
                array(
                    'taste' => 'Sweet',
                    'count' => 0,
                    'frequency' => 0,
                    'max' => 0,
                    'sum' => 0,
                ),
            );

// Summarize the frequency, maximum and avg intensity for each taste from the analyses
            foreach ($taste_summary as $k1 => $ts) {
                foreach ($taste_observations as $k2 => $to) {
                    if ($to['taste'] == $ts['taste']) {
                        echo("Summary taste = ".$ts['taste']." while Observed taste = ".$to['taste']." and Observed intensity = ".$to['intensity']."<br>");
                        $ts['frequency'] = $ts['frequency'] + 1;
                        echo("Incrementing Frequency for Taste ".$ts['taste']." to ".$ts['frequency']."<br>");
                        if ($to['intensity'] <> 0) {
                            $ts['count'] = $ts['count'] + 1;
                            echo("Incrementing Summary Count for Taste ".$ts['taste']." to ".$ts['count']."<br>");
                            $ts['sum'] = $ts['sum'] + $to['intensity'];
                            echo("Increasing Sum for Taste ".$ts['taste']." to ".$ts['sum']."<br>");
                            if ($to['intensity'] > $ts['max']) {
                                $ts['max'] = $to['intensity'];
                                echo("Changing Max for Taste ".$ts['taste']." to ".$ts['max']."<br>");
                            }
                        }
                    }
                }
            }
            print_r($taste_summary);

Here are the results I get - note the echo statements are showing that while the loops are executing it appears I am correctly accumulating the count, sum & max, but at the end of it all i still have zero values in my $taste_summary array:

Summary taste = Savory while Observed taste = Savory and Observed intensity = 1
Incrementing Frequency for Taste Savory to 1
Incrementing Summary Count for Taste Savory to 1
Increasing Sum for Taste Savory to 1
Changing Max for Taste Savory to 1
Summary taste = Spicy while Observed taste = Spicy and Observed intensity = 1
Incrementing Frequency for Taste Spicy to 1
Incrementing Summary Count for Taste Spicy to 1
Increasing Sum for Taste Spicy to 1
Changing Max for Taste Spicy to 1
Summary taste = Sweet while Observed taste = Sweet and Observed intensity =
Incrementing Frequency for Taste Sweet to 1
Summary taste = Sweet while Observed taste = Sweet and Observed intensity = 2
Incrementing Frequency for Taste Sweet to 2
Incrementing Summary Count for Taste Sweet to 1
Increasing Sum for Taste Sweet to 2
Changing Max for Taste Sweet to 2
Summary taste = Sweet while Observed taste = Sweet and Observed intensity = 1
Incrementing Frequency for Taste Sweet to 3
Incrementing Summary Count for Taste Sweet to 2
Increasing Sum for Taste Sweet to 3

Array ( [0] => Array ( [taste] => Bitter [count] => 0 [frequency] => 0 [max] => 0 [sum] => 0 ) [1] => Array ( [taste] => Creamy / Oily [count] => 0 [frequency] => 0 [max] => 0 [sum] => 0 ) [2] => Array ( [taste] => Dry / Tannic [count] => 0 [frequency] => 0 [max] => 0 [sum] => 0 ) [3] => Array ( [taste] => Salty [count] => 0 [frequency] => 0 [max] => 0 [sum] => 0 ) [4] => Array ( [taste] => Savory [count] => 0 [frequency] => 0 [max] => 0 [sum] => 0 ) [5] => Array ( [taste] => Sour [count] => 0 [frequency] => 0 [max] => 0 [sum] => 0 ) [6] => Array ( [taste] => Spicy [count] => 0 [frequency] => 0 [max] => 0 [sum] => 0 ) [7] => Array ( [taste] => Sweet [count] => 0 [frequency] => 0 [max] => 0 [sum] => 0 ) )
DarkBee
  • 16,592
  • 6
  • 46
  • 58
David
  • 13
  • 1
  • Your last taste observation in your example data does not have an `intensity`, is that on purpose? – CBroe Mar 29 '22 at 13:36
  • Yes that is intentional as it reflects the reality of my input data - sometimes there is no intensity, which is why I have two counters Frequency counts each time a taste is referenced, and count only those that have intensity values so I can calculate avg correctly. – David Mar 29 '22 at 15:03
  • This is solved BTW thanks to a reference I received - I've changed my loop now to properly reference the summary array when i want to update the values: – David Mar 29 '22 at 15:03

2 Answers2

1
// Initialize the taste summary array

Nah, I wouldn't; not like that. I'd start with an empty array, and then fill it dynamically.

If you use the taste as array key, instead of just plain numeric ones, you can shorten the necessary code to "look up" whether an entry for a taste already exists. If you want a normally indexed array as result, you can get that afterwards via array_values.

$taste_summary = [];
foreach($taste_observations as $taste_observation) {
    $taste_summary[$taste_observation['taste']] = [
        'taste' => $taste_observation['taste'],
        'count' => 1 + ($taste_summary[$taste_observation['taste']]['count'] ?? 0),
        'max' => max($taste_summary[$taste_observation['taste']]['max'] ?? 0, $taste_observation['intensity']),
        'sum' => $taste_observation['intensity'] + ($taste_summary[$taste_observation['taste']]['sum'] ?? 0)
    ];
}
ksort($taste_summary);
$taste_summary = array_values($taste_summary);
print_r($taste_summary);

I am using the null-coalescing operator ?? here, as a short way to check whether an item under a specific key already exists, and use 0 as default value in the count and sum calculations otherwise, more details on that operator can be found here, PHP ternary operator vs null coalescing operator

Live example: https://3v4l.org/GTZPD (Note that I added 'intensity' => 2 in your last input item, which was missing in your sample data.)

And I left out the frequency, because I didn't get what you actually wanted to put in there.

CBroe
  • 91,630
  • 14
  • 92
  • 150
0

You can not overwrite the original array values by updating the $value in the foreach loop.

One way to make this work is by passing the value by reference (& symbol):

foreach ($taste_summary as $k1 => &$ts) {
    foreach ($taste_observations as $k2 => &$to) {
        //....
    }
}

More information about references here: https://www.php.net/manual/en/language.references.php

DarkBee
  • 16,592
  • 6
  • 46
  • 58
naamhierzo
  • 345
  • 2
  • 8