0
    $users = [
    ['id' => 1, 'gender' => 'M', 'dob' => 1990, 'country' => 'IN', 'activity_score' => 34],
    ['id' => 2, 'gender' => 'M', 'dob' => 1980, 'country' => 'US', 'activity_score' => 9],
    ['id' => 3, 'gender' => 'F', 'dob' => 1993, 'country' => 'UK', 'activity_score' => 45],
    ['id' => 4, 'gender' => 'M', 'dob' => 1998, 'country' => 'IN', 'activity_score' => 0],
    ['id' => 5, 'gender' => 'F', 'dob' => 1997, 'country' => 'IN', 'activity_score' => 234],
    ['id' => 6, 'gender' => 'M', 'dob' => 1991, 'country' => 'UK', 'activity_score' => -6],
    ['id' => 7, 'gender' => 'F', 'dob' => 1992, 'country' => 'JP', 'activity_score' => 9],
    ['id' => 8, 'gender' => 'M', 'dob' => 1998, 'country' => 'US', 'activity_score' => 45],
    ['id' => 9, 'gender' => 'F', 'dob' => 2000, 'country' => 'JP', 'activity_score' => 5],
    ['id' => 10, 'gender' => 'M', 'dob' => 2006, 'country' => 'IN', 'activity_score' => 7],
    ['id' => 11, 'gender' => 'F', 'dob' => 1970, 'country' => 'US', 'activity_score' => 32],
    ['id' => 12, 'gender' => 'M', 'dob' => 2011, 'country' => 'IN', 'activity_score' => 21],
    ];
    $act_sum=0;
$act_sum1=0;
    foreach($users as $user){

   $age=date('Y')-$user['dob'];
   if($age>=16&& $age<=20)
   {
       $act_sum+=$user['activity_score'];

   }
    else if($age>20){
        $act_sum1+=$user['activity_score'];
    }
    }

without these if condition can it be possible by array functions itself? i have to find Sum activity score by age group 16-20, 20+

susana
  • 45
  • 6

3 Answers3

1

You can use a functional approach with the native array_reduce function, without loops involved.

$sumByAgeGroup = array_reduce($users, function($carry, $item) {
    $age = date('Y') - $item['dob'];
    if ($age > 20) {
        $carry['>20'] += $item['activity_score'];
    } elseif ($age >= 16 && $age <= 20) {
        $carry['16-20'] += $item['activity_score'];
    }
    return $carry;
}, ['16-20' => 0, '>20' => 0]);

var_dump($sumByAgeGroup);

Output:

Array
(
    [16-20] => 5
    [20+] => 402
)
JustCarty
  • 3,839
  • 5
  • 31
  • 51
William Perron
  • 1,288
  • 13
  • 18
  • This look great, what is the difference between array_map and array_reduce btw? Because in both case you use an array ($users here) and a callback function. I don't use a lot of array_function so sorry if the question is trivial ! – Mickaël Leger Apr 17 '18 at 13:09
  • 2
    `array_map` applies a modification (callback) on each element of the array, whereas `array_reduce` carries over the result of the callback on each iteration, allowing you to calculate sums and averages among other things. here is a nice and concise article on [Mapping, Filtering and Reducing in php](http://eddmann.com/posts/mapping-filtering-and-reducing-in-php/) – William Perron Apr 17 '18 at 13:12
0

Try this:

$min = 16;
$max = 20;
$newNumbers = array_filter(
    $users,
    function ($value) use($min, $max) {
        return (date('Y') - $value['dob']) >= $min && (date('Y') - $value['dob']) <= $max;
    }
);

$sum = 0;
foreach ($newNumbers as $value) {
    $sum += $value['activity_score'];
}

You were comparing an array with an integer, hence why the new array was empty.

This way I am determining the age (based on current year subtract birth year - this is not accurate; consider using a library like Carbon and using full dates) and from that, I was able to determine if the user was aged between the minimum and maximum values.

The foreach then just loops through the new set of users and adds their activity score up and stores it in a variable called sum.


Edit, following your edit

$min = 16;
$max = 20;
$sumInRange = $sumOutOfRange = 0;

$inRange = array_filter(
    $users,
    function ($value) use($min, $max) {
        return (date('Y') - $value['dob']) >= $min && (date('Y') - $value['dob']) <= $max;
    }
);

// https://stackoverflow.com/a/11822305/3578036
function udiffCompare($a, $b)
{
    return $a['id'] - $b['id'];
}

$outOfRange = array_udiff($users, $inRange, 'udiffCompare');

foreach ($inRange as $value) {
    $sumInRange += $value['activity_score'];
}

foreach ($outOfRange as $value) {
    $sumOutOfRange += $value['activity_score'];
}

var_dump(
    $sumInRange,
    $sumOutOfRange
);

The above code is very similar to the one used at the top of this answer, except this time I am storing two versions of the users array - one between the range and one out of the range.

Then it is simply a case of iterating over those new arrays and getting calculating the sum.

JustCarty
  • 3,839
  • 5
  • 31
  • 51
0

Try this maybe :

// Your result array with score by age group
$result = array(
    '16-20' => 0,
    '20+' => 0
);
// The current year
$current_year = date('Y');

// Loop throught users
foreach ($users as $user) {
    // I calcul the age of the user according to current_year
    $age = $current_year - $user['dob'];

    // If $user age is 16, 17, 18 or 19, I add his score
    if ($age < 20 && $age >= 16) {
        $result['16-20'] = $result['16-20'] + $user['activity_score'];
    }

    // If user is 20 or more
    if ($age >= 20) {
        $result['20+'] = $result['20+'] + $user['activity_score'];
    }
}

With :

var_dump($result);

I got this :

array (size=2)
    '16-20' => int 5
    '20+' => int 402

EDIT WITHOUT FOREACH :

// I create a function that return an array with the score of user by age
function get_score($user) {
    $result = array();
    $current_year = date('Y');

    $age = $current_year - $user['dob'];

    if ($age < 20 && $age >= 16) {
        $result['16-20'] = $user['activity_score'];
    }
    if ($age >= 20) {
        $result['20+'] = $user['activity_score'];
    }
    return $result;
}

// Then I create my $result array :
$result = array(
    '16-20' => array_sum(array_column(array_map( "get_score", $users), '16-20')),
    '20+' => array_sum(array_column(array_map( "get_score", $users), '20+'))
);

I don't use a lot array function to be honest so I'm sure we can do this a better way, but this one works here :)

I got the same result with var_dump($result');

Mickaël Leger
  • 3,426
  • 2
  • 17
  • 36