2013-06-03 4 views
2

У меня есть массив, который, например, выглядит следующим образом:Как рассчитать общее количество в массиве. PHP

$cases = array(23, 18, 5, 8, 10, 16); 

То, что я хочу выход быть является нарастающим итогом:

23, 41, 46, 54, 64, 80 

Некоторая информация, чтобы помочь прояснить: Этот массив в настоящее время заполняя линейный график, и моя цель - попытаться добавить строку, которая показывает совокупный прогресс каждый день. (Данные поступают из БД, так что я не могу просто изменить исходный массив)

+3

На какой части вы застряли? – PeeHaa

+0

PHP-логика для итерации по массиву и сохранения текущей суммы. – user2448754

+1

Вы хоть что-то пробовали? В чем была проблема, когда вы это пробовали? Где ты застрял? – PeeHaa

ответ

10

Самый простой способ, с O (N) сложности:

$original = array(23, 18, 5, 8, 10, 16); 

$total = array(); 
$runningSum = 0; 

foreach ($original as $number) { 
    $runningSum += $number; 
    $total[] = $runningSum; 
} 

var_dump($total); 
+0

+1. Пример учебника :) –

+0

+1 понравилось, что (-: – ncm

+0

Простой, простой, и вы правильно инициализировали свои переменные. :) Если ваш исходный список не является огромным или открытым итератором, это намного эффективнее, чем решения итератора/генератора , как в исполнении, так и в удобочитаемости (= эффективность обслуживания) – IMSoP

3

array_sum() возвратит сумму всех чисел в массиве, однако, добавил, если вы хотите running total, здесь идут:

$total = array(); 
$original = array(23, 18, 5, 8, 10, 16); 

foreach($original as $number) 
{ 
    $total[] = array_sum($total)+$number; 
} 

print_r($total); 
+0

Ваше право ... Я пропустил закрытую фигурную скобку. –

+0

Мои основные навыки математики идут под гору! –

+0

Невероятно! Обновлено, упрощено! –

1
<? 
$total = array(); 
$points = array(23, 18, 5, 8, 10, 16); 

while ($points) { 
$total[] = array_shift($points); 
echo 'point: '.array_sum($total); 
} 
?> 
7

Немного линии с array_map. Он выполняет итерацию по массиву, увеличивая фактическую общую сумму и возвращает ее.

$actual_sum = 0; 
$running_total = array_map(function ($entry) use (&$actual_sum) { return $actual_sum += $entry; }, $cases); 
+0

Надеюсь, вы заметили комментарии в ответ на @PhilCross. Я собираюсь удалить свой ответ, а также отвечу на ваш ответ (+1). это также верно. – ncm

+0

@immiso Да, я их видел, я просто не заметил хронологического порядка; вот почему я был в замешательстве. – bwoebi

+0

goooooooooooood – ncm

2
$cases = array(23, 18, 5, 8, 10, 16); 
$running = array_reduce(
    $cases, 
    function ($counter, $value) { 
     static $summer = 0; 
     $summer += $value; 
     $counter[] = $summer; 
     return $counter; 
    }, 
    array() 
); 

var_dump($running); 
+0

oooh, как сложно: o Это возможно, но на самом деле слишком много инструкций для маленькой задачи. – bwoebi

+3

Вы уже дали более простой ответ, я просто напомнил читателям, что PHP имеет большой набор возможностей. –

+0

Я не делал это без изменений, поскольку это не так, но это больше злоупотребляет функцией array_reduce, чем использование другой подходящей функции здесь. – bwoebi

2

Aaaaand другой вариант с array_walk, что ИМХО наиболее естественно:

$cases = array(23, 18, 5, 8, 10, 16); 
$totals = array(); 
array_walk($cases, function($v) use (&$totals) {$totals[] = end($totals) + $v;}); 

See it in action ,

4

Представляя данный RunningTotalIterator решение, в основном написана, чтобы дополнить другие ответы:

class RunningTotalIterator extends ArrayIterator 
{ 
    private $sum; 

    public function rewind() 
    { 
     parent::rewind(); 
     $this->sum = $this->valid() ? parent::current() : 0; 
    } 

    public function current() 
    { 
     return $this->sum; 
    } 

    public function next() 
    { 
     parent::next(); 
     if ($this->valid()) { 
      $this->sum += parent::current(); 
     } 
    } 
} 

$result = iterator_to_array(new RunningTotalIterator(array(23, 18, 5, 8, 10, 16))); 
print_r($result); 
+0

У вас есть потенциальная логическая ошибка, когда перемотка может привести к недействительной сумме. Вместо этого установите его в '0' перед' if $ this-> valid() 'check in rewind() или в ветке else, ... – ircmaxell

+0

@ircmaxell Это правда, это было намеренно опущено, потому что пустой массив даст пустой массив ... вызов 'current()' на пустом итераторе не определен ни afaik ... но я его поменяю тем не менее :) –

+0

редактирование выглядит хорошо. Но это возможно в случае, если я изменяю итератор (например, отключая значение) ... – ircmaxell

4

с помощью генераторов (новый 5,5 функций):

function getRunningTotal(array $array) { 
    $generator = function(array $array) { 
     $total = 0; 
     foreach ($array as $key => $value) { 
      $total += $value; 
      yield $key => $total; 
     } 
    }; 
    return iterator_to_array($generator($array)); 
} 

Если вы хотите сохранить результат в качестве итератора , просто верните $generator($array) непосредственно ...

Способ, которым это работает, заключается в том, что двигатель внутренне создает генератор (whic h действует как итератор), который «возвращает» все, что дается. Таким образом, сохраняя свою собственную текущую сумму внутри функции, мы можем «вернуть» ее вызывающему. Довольно прямолинейно ...

+0

+1. (@NikiC должен был написать это) Мне очень нравится этот подход, по крайней мере, потому, что он не слишком большой и портативный. – bwoebi

+0

@bwoebi не негабаритный, да (потому что генераторы - это буквально итераторные сокращения) ... портативный (по сравнению с полномасштабными итераторами), спорный, если вы не имеете в виду, что вам проще копировать и вставлять ;-) –

+0

@ jack more portable ... ircmaxell убедил мне, что мы можем просто скопировать его, без изменений, если мы хотим перебирать его, хотим, чтобы он был как массив и т. д. – bwoebi