YasirPoongadan
YasirPoongadan

Reputation: 749

Given an array of numeric ranges, find the sum of values from an associative array where the key falls within a range

$array = [
  2 => 5,
  8 => 3,
  4 => 7,
  11 => 1,
  9 => 2,
];

I want the sum of values where the key fits in a specific period like 1-5 or 6-10.

For my given input, I need this output:

[
    '1-5' => 12, # 5 + 7
    '6-10' => 5, # 3 + 2
]

Upvotes: -2

Views: 1778

Answers (3)

mickmackusa
mickmackusa

Reputation: 48031

Considering that you might want to see all groups/ranges represented in the result and that some data might not qualify for any group, I've extended the sample data to show these considerations.

Use a conditionally broken nested loop with minimum and maximum numbers which will add amounts to respective groups/ranges.

array_map() is used to establish a 0 value for all declared groups/ranges.

Code: (Demo)

$array = [
    2 => 5,
    4 => 1,
    8 => 3,
    0 => 17,
    9 => 2,
    11 => 67
];

$ranges = [
    '1-5' => ['min' => 1, 'max' => 5],
    '6-10' => ['min' => 6, 'max' => 10],
    '1000-5000' => ['min' => 1000, 'max' => 5000],
];

$result = array_map(fn() => 0, $ranges);
foreach ($array as $num => $amount) {
    foreach ($ranges as $rangeName => ['min' => $min, 'max' => $max]) {
        if ($num >= $min && $num <= $max) {
            $result[$rangeName] += $amount;
            break;
        }
    }
}
var_export($result);

If you want to minimize iterations, you can remove elements after they qualify or get disqualified. This will "consume"/"destroy" the data in $array. Demo

$result = [];
foreach ($ranges as $rangeName => ['min' => $min, 'max' => $max]) {
    $result[$rangeName] = 0;
    foreach ($array as $num => $amount) {
        if ($num < $min) {
            unset($array[$num]);
        } elseif ($num <= $max) {
            $result[$rangeName] += $amount;
            unset($array[$num]);
        }
    }
}
var_export($result);

If your number ranges aren't gigantic, you can expand the hyphenated ranges into populated ranges, flip, filter, then sum for each range. The performance may not be awesome on "large" number ranges, so if efficiency is of high importance run some benchmarks. Here's a function-style script that mostly implements @rozsazoltan's advice but dynamically processes an array of hyphenated range strings. Demo

$ranges = ['1-5', '6-10', '1000-5000'];

var_export(
    array_reduce(
        $ranges,
        fn($result, $range) => $result
            + [$range => array_sum(array_intersect_key($array, array_flip(range(...sscanf($range, '%d-%d')))))],
        []
    )
);

Output (from any of above):

array (
  '1-5' => 6,
  '6-10' => 5,
  '1000-5000' => 0,
)

Upvotes: 1

rozsazoltan
rozsazoltan

Reputation: 8835

You can extract the specific keys from an array, and then use array_sum to add the extracted values.

$array = [
  2 => 5,
  4 => 1,
  8 => 3,
  9 => 2,
];

// the range() function gives the from-to values
$range = range(1, 5); // [0 => 1, 1 => 2, 2 => 3, 3 => 4, 4 => 5]
// move the 1-2-3-4-5 values to key
$rangeFlip = array_flip($range); // [1 => 0, 2 => 1, 3 => 2, 4 => 3, 5 => 4]
// search for the keys in the $array that match the keys of $rangeFlip
$rangeArray = array_intersect_key($array, $rangeFlip);
/*
[
  2 => 5,
  4 => 1,
]
*/
// sum the values of $rangeArray
$result = array_sum($rangeArray); // 5 + 1 = 6
$array = [
  2 => 5,
  4 => 1,
  8 => 3,
  9 => 2,
];

$range1 = range(1, 5);  // [1, 2, 3, 4, 5]
$range2 = range(6, 10); // [6, 7, 8, 9, 10]

$result = [];
$result['1-5'] = array_sum(array_intersect_key($array, array_flip($range1)));
$result['6-10'] = array_sum(array_intersect_key($array, array_flip($range2)));

And then, from the previous logic, we can write our own function that takes the array containing the data and the range to specify which key values we are interested in, from-to.

$array = [
  2 => 5,
  4 => 1,
  8 => 3,
  9 => 2,
];

function array_sum_range($array, $range) {
    return array_sum(array_intersect_key($array, array_flip($range)));
}

$result = [];
$result['1-5'] = array_sum_range($array, range(1, 5));
$result['6-10'] = array_sum_range($array, range(6, 10));

Upvotes: 0

zzlalani
zzlalani

Reputation: 24384

Try this code.. Not a rocket science..

function sumArray($array, $min, $max) {
   $sum = 0;
   foreach ($array as $k => $a) {
      if ($k >= $min && $k <= $max) {
         $sum += $a;
      }
   }
   return $sum;
}

echo sumArray($array, 1, 5);

Upvotes: 4

Related Questions