开发者

Porting a C++ map with std::accumulate to PHP

I'm not terribly well versed with array manipulation in PHP, so I have a simple porting question. In C++ I have a map std::map<int, int>, for which the implicit ordering on the key is a crucial part of the structure. What I want to do is to sum up all the values for an initial range of keys, which I do like this:

// accumulate helper, since "value_type" is "pair<int, int>"
int pair_adder(int n, const std::map<int, int>::value_type & p) { return n + p.second; }

// To add up values for keys up to N:
int total_value_up_to_time_N(int N)
{
  return std::accumulate(mymap.begin(), mymap.upper_bound(N), 0, pair_adder);
}

What would be an idiomatic way to write this data structure and accumulator in PHP?

To explain the context: The data structure is a simple time series, and I want to know how much I have accumulated at time N. The C++ map is always sorted by key, so I can add elements mymap[time] = value; in any order, and the map always contains the elements in time order.

To explain the accumulation: The accumulate function sums up all the map's values whose keys are no greater than N. For example, take this map:

 mymap = { { 1, 20}, {2, 30}, {3, -10}, {4, 15} };

Then for N = 2 I accumulate 50, for N = 3 I accumulate 40, and for N = 12 I accumulate 55.


Update: I just realized that actua开发者_如何转开发lly there's no reason why each timestamp should occur only once, so the data structure should really be a std::multimap<int, int>. The same accumulation function works verbatim, but if the PHP solution requires the time to be an array key, than that would no longer work. But this is not strictly important; I believe a solution in which each time is required to be unique will suffice.


I'm not super familiar with C++, but I'll try to give you a quick overview of arrays in PHP, then answer your question about summing.

Every array in PHP can be thought of as an ordered map. Unlike C++, there are no restrictions on type, an array is simply a map from key to value.

To create an array, you can use the following:

$arr = array();

To add items to the array, there are two ways to do it. First, you can use the [] operator to add a new element on to the end of the array. The key for this element will be (highest int key + 1), with the first key starting at zero. For example:

$arr[] = 1;
$arr[] = 2;
$arr[] = 4;

At this point, $arr is now a map with the following keys / values:

0 => 1
1 => 2
2 => 4

We can also add specific keys and values:

$arr[42] = 'cool';
$arr['foo'] = 'bar';

At this point the map will look as follows:

0 => 1
1 => 2
2 => 4
42 => 'cool'
'foo' => 'bar'

There's quite a few functions built in to PHP for working with arrays. For example, there are functions for sorting arrays (both by key and value, and in user defined ways), combining arrays, searching arrays, applying functions to all elements, reducing arrays, etc. Furthermore, the PHP construct foreach can be used to iterate over an array. Use it as follows:

foreach ($arr as $key => $value) {
    echo 'Value of key ' . $key . ' is ' . $value;
}

Now, to address your question:

What I want to do is to sum up all the values for an initial range of keys

Take note that if you add values in order, they will be in order in the array. If this is not the case, sort the array beforehand, then do the following:

$sum = array_sum(array_slice($arr, 0, $n));

Hope this helps!


Unfortunately, the PHP array map/reduce functions only map over values, not keys. If your map is using PHP key => value arrays, you'll need some tricks to filter out the values whose keys have a certain value. The easiest is a straight forward loop:

$map = array(1 => 20, 2 => 30, 3 => -10, ...);
$n = 3;

$result = 0;
foreach ($map as $key => $value) {
    if ($key <= $n) {
        $result += $value;
    }
}

From here you can of course get creative though:

$result = array_sum(array_intersect_key(
    $map,
    array_flip(array_filter(array_keys($map), function ($key) use ($n) {
        return $key <= $n;
    }))
));

Or:

$result = array_sum(array_map(function ($key, $value) use ($n) {
    return $key <= $n ? $value : 0;
}, array_keys($map), $map));

If you're using a more C++ like map, which in PHP would be an array of arrays, that simplifies the problem:

$map = array(array('key' => 1, 'value' => 20), array(...), ...);

$result = array_reduce($map, function ($v, $m) use ($n) {
    return $v + ($m['key'] <= $n ? $m['value'] : 0);
});


Well, there’s array_reduce and a map is basically just an array. Hence:

$result = array_reduce($your_array, function($a, $b) { return $a + $b; });

should do the trick. Or just use array_sum (thanks, deceze).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜