Ітераційні часткові суми


23

Часткові суми списку цілих чисел [a 1 , 2 , a 3 , ..., a n ] є

s 1 = a 1
s 2 = a 1 + a 2
s 3 = a 1 + a 2 + a 3
...
s n = a 1 + a 2 + ... + a n

Тоді ми можемо взяти список часткових сум [s 1 , s 2 , s 3 , ..., s n ] і знову обчислити його часткові суми для створення нового списку тощо.

Пов'язане: Ітераційні різниці вперед

Вхід:

  • Непорожній список цілих чисел
  • Позитивна кількість повторень,

Вихід: надрукуйте або поверніть список цілих чисел, що є результатом отримання часткових сум у багато разів.

Виграє найменше байт. Вбудовані в порядку добре, навіть якщо вони прямо вирішують проблему.

Тестові приклади:

f([-3, 4, 7, -1, 15], 1) == [-3, 1, 8, 7, 22]
f([-3, 4, 7, -1, 15], 3) == [-3, -5, 1, 14, 49]

Табло:


Чи повинні аргументи бути в одному порядку, чи може кількість повторень перейти до списку чисел?
kirbyfan64sos

@ kirbyfan64sos Або замовлення.
xnor

Відповіді:


14

J, 5 байт

+/\^:

Спробуйте його в Інтернеті на J.js .

Як це працює

  • /\ є прислівником (функція, яка займає лівий аргумент), що кумулятивно зменшує своїм аргументом.

  • Таким чином +/\є дієсловом сукупної суми .

  • ^:- силова сполука ; (f ^: n) yзастосовується fв цілому nдо y.

  • Послівник-сполучник поїзда +/\^:утворює прислівник, який повторюється +/\стільки разів, скільки зазначено в його (лівому) аргументі.

    x (+/\^:) yрозбирається як (x (+/\^:)) y, що еквівалентно виконанню (+/\^:x) y.

Дякуємо @Zgarb за допомогу в поясненні.


13

Математика, 19 байт

Ну, якщо з вбудованими файлами все в порядку ...

Accumulate~Nest~##&

Визначає функцію з тією ж підписом, що і приклади в виклику. Я майже впевнений, завдяки довгому імені, Accumulateщо це легко переможеться з мов для гольфу та сімейства APL. :)

Щоб детальніше розглянути коментар LegionMammal978 для тих, хто не має Mathematica:

##являє собою послідовність параметрів функції (це як список, який автоматично «заплітається» скрізь, де він вставлений, якщо ви більше знайомі з цим терміном з обраної вами мови). ~Є синтаксичним цукром для функції ІНФІКС виклику, так що якщо ми викликаємо функцію з параметрами listі nі розширити всі, ми отримаємо:

Accumulate~Nest~##
Nest[Accumulate, ##]
Nest[Accumulate, list, n]

Що трапляється, саме цей аргумент для того , очікуваного Nest.


Це цікаво, використовуючи позначення інфіксації для 3 аргументів, використовуючи SlotSequence...
LegionMammal978

9

Haskell, 26 23 байти

(!!).iterate(scanl1(+))

Це визначає анонімну функцію, яку викликають так:

> let f = (!!).iterate(scanl1(+)) in f [-3,4,7,-1,15] 3
[-3,-5,1,14,49]

Завдяки @nimi за збереження 3 байтів.

Пояснення

(!!).                    -- Index by second argument from
     iterate(         )  -- the infinite list obtained by iterating
             scanl1(+)   -- the partial sums function (left scan by +) to first argument

Дуже хороша! І дякую за пояснення!
Джейк

2
Go pointfree, то ви можете навіть не вказувати ім'я для функції: (!!).iterate(scanl1(+)).
німі

@nimi Дякую! Я якось обґрунтував, що композиція тут не спрацює на мою користь ...
Zgarb

9

APL, 9 8 байт

{+\⍣⍺⊢⍵}

Це визначає діадичну функцію, яка приймає ітерації та список як аргументи зліва та справа.

Дякуємо @NBZ за те, що виграли 1 байт!

Спробуйте його в режимі он-лайн на TryAPL .

Як це працює

  • і є лівим і правим аргументами функції.

  • +\ є кумулятивним зменшенням на суму.

  • ⍣⍺повторює попередні часи оператора .

  • ⊢⍵застосовує функцію ідентичності до .

    Це коротший спосіб розбору коду як (+\⍣⍺)⍵замість +\⍣(⍺⍵).

У поєднанні ми застосовуємо +\в цілому раз


@AlexA. Тоді це було +\⍣⎕⊢⎕б неприйнятно? ( це як Python input()).
marinus

1
@marinus Чи справді це друкується за межами REPL? Єдині перекладачі настільних комп’ютерів, які я маю, вимагатимуть призначити після.
Денніс

5

Матлаб, 41 байт

function f(l,n);for i=1:n;l=cumsum(l);end

Досить прямо. Я все ще думаю, що це дуже прикро не мати вбудованого способу внесення детально визначених анонімних функцій або прив'язки до рекурсій.

Безголівки:

function f(l,n);
for i=1:n;
    l=cumsum(l);
end

5

JavaScript (ES6) 38

Напрочуд мало, використовуючи .map рекурсивно

f=(l,n,t=0)=>n?f(l.map(x=>t+=x),n-1):l

function test()
{
  var n, v, i = I.value
  v = i.match(/\-?\d+/g).map(x=>+x)
  n = v.pop()
  console.log(v,n)
  O.innerHTML = I.value + ' -> ' + f(v,n) + '\n' + O.innerHTML;
}

test()
<input id=I value='[-3, 4, 7, -1, 15], 3'><button onclick="test()">-></button>
<pre id=O></pre>


5

К, 7 3 байти

{y+\/x}

Дуже схожий на J-рішення. +\точно виконує часткову суму, і коли /вона надається монадичним дієсловом і цілим лівим аргументом, воно повторює задану кількість разів, як цикл "для". Решта - просто загортати його акуратно, щоб відповідати порядку аргументів.

  {y+\/x}[-3 4 7 -1 15;1]
-3 1 8 7 22
  {y+\/x}[-3 4 7 -1 15;3]
-3 -5 1 14 49

Випробували в Коні та ОК .

Редагувати:

Якщо мені дозволено відміняти аргументи, як визначено @ kirbyfan64sos, я можу повністю відмовитися від обгортання функції:

+\/

Називається як:

+\/[3;-3 4 7 -1 15]

Це працює нормально як у k2.8, так і в k5. Він не працює в ОК, оскільки інтерпретатор ще не підтримує висловлені (так звані "прогнозовані") прислівники, і, здається, він не працює належним чином у Коні з менш зрозумілих причин.

редагувати : Станом на кілька днів тому, +\/рецептура також працює в oK.


1
Аргументи можна змінити , тому я думаю, що ви зможете поголити кілька байтів.
kirbyfan64sos

3 +\/ -3 4 7 -1 15працює добре в Коні, але ви не можете призначити її функції. Дивно ...
Денніс

Так, Кона явно не трактує 3+\/-3 4 7 -1 15те саме, що +\/[3;-3 4 7 -1 15]- змушує мене замислитись, чи вони поводяться з першим як особливий синтаксичний випадок.
JohnE


4

Джулія, 29 байт

f(x,y)=y>0?f(cumsum(x),y-1):x

Це дійсно не потребує особливих пояснень. Це рекурсивна функція, якщо y==0тоді просто вивести x. В іншому випадку декрементуйте y, виконайте сперму та повторіть. Напевно, не найголовніше можливе рішення Юлії, я все ще працюю над цим.


4

Лабіринт , 73 байти

;?
,"
;
#
#;}=
;  #
"#;(
_  ;={()"
#;; ( { "
  ; { !\(@
+=( =
" " "
":{:"

Минув час, коли я щось відповів у Лабіринті, і це здавалося здійсненним. :)

Формат введення - це плоский список із початковою кількістю ітерацій (а потім списку, до якого слід застосувати часткові суми). Розмежувачі мають значення не все, доки після останнього цілого числа немає символу, тому ви можете використовувати щось читабельне, наприклад:

3 | -3, 4, 7, -1, 15

Результат розділений новим рядком:

-3
-5
1
14
49

4

R, 75 байт

Довго, але по-іншому потрібно ... обчислити бажану послідовність безпосередньо замість сукупних сум:

function(x,n)sapply(1:length(x),function(i)sum(x[1:i]*choose(i:1+n-2,n-1)))

Зауваживши, що коефіцієнти доданків xi для cumsum ^ n (x) - це діагоналі трикутника Паскаля. тобто

cumsum^3(x) = choose(2,2) * x1, choose(3,2) * x1 + choose(2,2) *x2, choose(4,2) * x1 + choose(3,2) * x2 + choose(2,2) * x3, ....

редагувати: зробити функцію


4

Пітон 2, 67

Для цього використовується те саме підсумок, що і Ентоні Ройтман , і така сама рекурсія, як і Морган Трапп .

f=lambda l,n:f([sum(l[:i+1])for i in range(len(l))],n-1)if n else l

Я розробив це рішення ще до того, як побачив їхнє, і тоді мені здалося просто легше розмістити його як відповідь, а не коментар до того чи іншого.


4

Пітон, 113 93 89 76 байт

def f(l,n):
 for i in[0]*n:l=[sum(l[:j+1])for j in range(len(l))];
 print(l)

Він працює для обох тестових випадків. Завдяки статусу, Морган Трапп і Рут Франклін за те, що вони допомогли мені переграти програму до 93, 89 і 76 байт відповідно.


1
Ви можете вирізати ряд байтів, змінивши другий цикл на розуміння списку. Тобто k=[sum(l[:j+1])for j in range(len(l))]. Потім з ;k=lпозначкою на кінці цього ви можете натиснути це все на одну лінію за допомогою for iпетлі.
Статус

1
Ви можете перемістити k=[sum(l[:j+1])for j in range(len(l))];l=kна той самий рядок, що і цикл for, щоб зберегти 2 байти та видалити пробіл між аргументами f, щоб зберегти ще один байт.
Морган Трапп

Як ви не використовуєте значення i, ви можете замінити for i in range(n)з for i in[0]*n(бо все , що ви дбаєте про те , довжина не елементи списку). І я думаю, що ви можете це зробити, не використовуючи допоміжний список k, просто змінивши аргумент l.
Рут Франклін

4

Гол> <> 0,3.10 , 22 байти

SI
C>rFlMF:}+
NRl<C}<;

Першим цілим числом вважається ітераційний номер, а решта складають список. Остаточний список виводиться розділеним рядком.

Мова ще досить молода і нестабільна, але оскільки я досить налаштований на цих операторів, я подумав, що це буде добре.

Пояснення

SI            Read integer, moving down on EOF (first line runs as loop)
r             Reverse stack, putting iteration number on top

[outer loop]
F             Do #(iterations) times

[inner loop]
lMF           Do #(length of stack - 1) times
:             Duplicate top of stack
}             Rotate stack rightward (top goes to bottom)
+             Add the top two elements of the stack
C             Continue inner loop, moving down from F when loop is over

}             Rotate once more
C             Continue outer loop, moving down from F when loop is over

lRN           Print stack as (num + newline)
;             Halt

Щоб зрозуміти, чому це працює, спробуємо невеликий приклад [5 2 1]:

[5 2 1] -- : --> [5 2 1 1] -- } -->  [1 5 2 1]  -- + --> [1 5 3]
[1 5 3] -- : --> [1 5 3 3] -- } -->  [3 1 5 3]  -- + --> [3 1 8]

-- } --> [8 3 1]

3

Пітон, 52 байти

f=lambda l,n:n*l and f(f(l[:-1],1)+[sum(l)],n-1)or l

Рекурсивна функція, яка повторюється як у списку, так lі за кількістю ітерацій n. Давайте розбимо його.

Спочатку розглянемо рекурсивну функцію, gяка повторила часткову суму лише один раз.

g=lambda l:l and g(l[:-1])+[sum(l)]

Для порожнього списку lце повертається lсам, порожній список. В іншому випадку останнє введення часткових сум l- це загальна сума l, яка додається до рекурсивного результату для всіх, крім останнього елемента l.

Тепер давайте розглянемо функцію, fяка застосовується gдля nітерацій.

f=lambda l,n:n and f(g(l),n-1)or l

Коли nце є 0, це повертає список lнезмінним, а в іншому випадку застосовується gодин раз, тоді викликується fрекурсивно, залишившись меншою кількістю ітерацій.

Тепер давайте ще раз розглянемо власне код, який поєднує дві рекурсії в одну функцію. Ідея - трактувати g(l)як особливий випадок f(l,1).

f=lambda l,n:n*l and f(f(l[:-1],1)+[sum(l)],n-1)or l

Ми взяли f(g(l),n-1)з попереднього визначення, розширенеg(l) в g(l[:-1])+[sum(l)], а потім замінюються g(_)з f(_,1)до приурочені рекурсивним викликам до f.

Для базового випадку ми хочемо повернутися lколи-небудь n==0або l==[]. Ми поєднуємо це, зазначаючи, що або один з n*lних є порожнім списком, який є Falsy. Отже, ми повторюємо, коли n*lце не порожньо, і повертаємося в lіншому випадку.

Незважаючи на те, що є два рекурсивні дзвінки f, це не викликає експоненціального підриву рекурсивного визначення чисел Фібоначчі, а залишається квадратичним.


3

C ++ (61 + 17 = 78 байт)

#include<numeric>
void f(int*a,int*e,int n){for(;n--;)std::partial_sum(a,e,a);}

Тестовий випадок:

#include <iostream>
#include <iterator>

int main() {
    int a[] { -3, 4, 7, -1, 15 };
    f(a, std::end(a), 3);
    for (auto i : a)
        std::cout << i << " ";
}

Це вимагає невеликої свободи із специфікацією: він використовує масив у стилі С, передаючи покажчики на початок та кінець масиву. Внутрішнє, як бачите, це лише надзвичайно всередині тонка обгортка std::partial_sumв стандартній бібліотеці. Замість того, щоб фактично повернути отримане значення, воно просто модифікує масив, який передається.

Якщо ми не проти підштовхувати визначення речей до межі (і, можливо, трохи далі), ми можемо визначити "функцію" в лямбдаському виразі:

#include<numeric>
#include <iostream>
#include <iterator>

int main() {
    int a[] { -3, 4, 7, -1, 15 };
    int *e = std::end(a);
    int n=3;

    auto f=[&]{for(;n--;)std::partial_sum(a,e,a);};

    f();
    for (auto i : a)
        std::cout << i << " ";
}

Це зводить визначення функції (-подібного об’єкта) до цього фрагмента:

[&]{for(;n--;)std::partial_sum(a,e,a);};

... на 40 байт (+17 для #include).


Вау, я не очікував, що STL матиме alg для підрахунку часткових сум.
Зереги

1
@Zereges: Ніхто не очікує, що іспанська інквізиція .... о, чекайте, ми робимо C ++, а не Python. Мої вибачення.
Джеррі Труну


2

Haskell, 52 47 байт

Перший в історії код "гольф", і я дуже новачок в Haskell, тому коментарі з радістю вітаються! У питанні не було зрозуміло, який необхідний формат виклику функції, чи сприйнятий він аргументом до програми, тому я використав знак оклику як ідентифікатор функції, щоб зберегти пару пробілів.

0!a=a
i!a=(i-1)![sum$take j a|j<-[1..length a]]

Використання (GHCi):

$ ghci partialsums.hs
GHCi, version 7.6.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
[1 of 1] Compiling Main             ( partialsums.hs, interpreted )
Ok, modules loaded: Main.
*Main> 1![-3, 4 ,7 ,-1 ,15]
[-3,1,8,7,22]
*Main> 3![-3, 4 ,7 ,-1 ,15]
[-3,-5,1,14,49]

Ласкаво просимо до коду гольфу! Зазвичай це відповідність коротше, ніж використовувати гвардії, наприклад 0!a=a i!a=....
xnor

Дякую @xnor - я раніше використовував 'xs' під час створення початкового коду, і, мабуть, пропустив його, коли я змінив код у публікації. Відредаговано.
Джейк

Бо sum(take j a)ви можете уникнути паронів, роблячи це sum$take j a, використовуючи високий пріоритет $.
xnor

Дякую за твою допомогу! Я чомусь опинився під враженням, яке $матиме перевагу над синтаксисом (і спробуйте оцінити решту рядка за станом). Звичайно, це навіть не мало б сенсу.
Джейк


2

C #, 52 + 85 = 148 137 байт

using E=System.Collections.Generic.IEnumerable<int>;

і

E I(E s,int i){int t=0;return i<1?s:I(System.Linq.Enumerable.Select(s,v=>t+=v),i-1);}

Він використовує неортодоксальні практики ( v=>t+=v), але це PPCG. Також врахуйте обмеження глибини укладання.


2

Пітон 3, 73

Можливо, можливо, можна було би відіграти трохи далі.

def f(n,i):
 p=0;c=[]
 for m in n:p+=m;c+=[p]
 f(c,i-1)if i else print(n)

Ця версія використовує numpy, який трохи схожий на обман, але ось це:

Пітон 3 (з нумером), 72

from numpy import*
def f(n,i):
 if i:c=cumsum(n);f(c,i-1)
 else:print(n)

2

C ++ 14, 102 103 94 + 17 (включають) = 111 байт

#include<vector>
auto f(std::vector<int>a,int n){for(;n--;)for(int i=0;i<a.size()-1;++i)a[i+1]+=a[i];return a;}

Безумовно, з тестовим кейсом

#include <vector>
#include <iostream>

auto f(std::vector<int> a, int n)
{
    for (; n--;)
        for (int i = 0; i < a.size() - 1; ++i)
            a[i + 1] += a[i];
    return a;
}


int main()
{
    auto t = f({-3, 4, 7, -1, 15}, 3);
    for (int i : t)
        std::cout << i << " ";
}

Покладається на порядок оцінювання. Не впевнений, це UB чи ні, але працює, це залежить від компілятора, тому я змінив його.


Замість того, щоб рахувати jвід 0 до n, підраховуйте nдо 0. Дає 97 байт по моєму підрахунку.
Джеррі Ковф

@JerryCoffin Спасибі ..
Зерегес


1

Бурлеск, 10 байт

{q++pa}jE!

загалом це не дуже ефективно, але це робить свою справу.

blsq ) {-3 4 7 -1 15} 1 {q++pa}jE!
{-3 1 8 7 22}
blsq ) {-3 4 7 -1 15} 3 {q++pa}jE!
{-3 -5 1 14 49}

1

C ++ 14, 67 байт

Як безіменна лямбда змінює свій вклад, вимагаючи c як контейнер з випадковим доступом, як vector<int>.

[](auto&c,int n){while(n--)for(int i=0;i++<c.size();c[i]+=c[i-1]);}


1

Желе , 3 байти

SƤ¡

Спробуйте в Інтернеті!

Це мій ( містер Xcoder) ) метод.

Желе , 3 байти

+\¡

Спробуйте в Інтернеті!

Це клір коінхерінг .

Спосіб №1

SƤ¡ - Повна програма, діадик.

  ¡- застосовувати повторно, N разів.
 Ƥ - Позначте попереднє посилання на префікси списку.
S - сума.
     - Результат неявно

Спосіб №2

+ \ ¡- Повна програма, діадик.

  ¡- застосовувати повторно, N разів.
 \ - Сукупне зменшення на:
+ - Доповнення.

0

Аксіома 213 47 байт

m(a,b)==(for i in 1..b repeat a:=scan(+,a,0);a)

ungolf і якийсь приклад

 (3) -> [m([-3,4,7,-1,15],1), m([-3,4,7,-1,15],3)]
    Compiling function l with type List Integer -> List Integer
    Compiling function m with type (List Integer,Integer) -> List
       Integer

    (3)  [[- 3,1,8,7,22],[- 3,- 5,1,14,49]]
                                                       Type: List List Integer
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.