Forum Discussion

Dicken's avatar
Dicken
Post Prodigy
2 months ago
Solved

Rolling accumulation

Hi,
I have been trying various methods of a rolling accumultion or bucketiing;  so  buckets of 3  =  {1..10} = 
{  {1}, {1,2}, { 1,2,3}, { 2,3,4} , {3,4,5}, {4,5,6}, {5,,6.7}, { 6,7,8} , { 7,8,9}, { 8,9,10} 

so there is always adding index and firstN / lastN as a table,
but i have these two methods with generate or transform;

let
  alist = {1 .. 15},
  window = 3,
  bucket = List.Generate(
    () => 1,
    each _ <= List.Count(alist),
    each _ + 1,
    each if _ < 4 then List.Range(alist, 0, _) else List.Range(alist, _ - window, window)
  )
in
  bucket



let
  alist = {1 .. 15},
  window = 3,
  pos = {1 .. List.Count(alist)},
  bucket = List.Transform(
    pos,
    (x) => if x < 4 then List.Range(alist, 0, x) else List.Range(alist, x - window, window)
  )
in
  bucket

a slightly efficient method seems to be to pad the list with zeros, so here 2 window - 1 ,
which removes the logical test but does meant the first is {0,0,1}

has anyone any other approaches using different functions? perhaps using custom comparer in
groupby ?

Richard 




  • Dicken please try with: 

    let
        alist = {1 .. 15},
        window = 3,
        pad = List.Repeat({0}, window - 1),           // {0, 0}
        padded = List.Combine({pad, alist}),          // {0,0,1,2,...,15}
        positions = {0 .. List.Count(alist) - 1},     // 0-based indices for final result
        buckets = List.Transform(
            positions,
            each List.Range(padded, _, window)        // always take exactly 'window' items
        )
    in
        buckets
  • Dicken Another option could be with List.Accumulate: 

    let
        alist = {1 .. 15},
        window = 3,
        buckets = List.Accumulate(
            {1 .. List.Count(alist)},
            {},
            (state, current) => 
                state & {
                    if current <= window 
                    then List.Range(alist, 0, current)
                    else List.Range(alist, current - window, window)
                }
        )
    in
        buckets

7 Replies

  • Dicken Another option could be with List.Accumulate: 

    let
        alist = {1 .. 15},
        window = 3,
        buckets = List.Accumulate(
            {1 .. List.Count(alist)},
            {},
            (state, current) => 
                state & {
                    if current <= window 
                    then List.Range(alist, 0, current)
                    else List.Range(alist, current - window, window)
                }
        )
    in
        buckets
    • Dicken's avatar
      Dicken
      Post Prodigy

      especially like the accumulate version. 

  • Dicken please try with: 

    let
        alist = {1 .. 15},
        window = 3,
        pad = List.Repeat({0}, window - 1),           // {0, 0}
        padded = List.Combine({pad, alist}),          // {0,0,1,2,...,15}
        positions = {0 .. List.Count(alist) - 1},     // 0-based indices for final result
        buckets = List.Transform(
            positions,
            each List.Range(padded, _, window)        // always take exactly 'window' items
        )
    in
        buckets
  • Dicken also you can try with List.Generate:

    let
        alist = {1 .. 15},
        windowSize = 3,
        result = List.Generate(
            () => [idx = 0, win = {}],
            each [idx] < List.Count(alist),
            each [
                idx = [idx] + 1,
                win = if [idx] < windowSize 
                      then List.Range(alist, 0, [idx] + 1)
                      else List.Range(alist, [idx] - windowSize + 1, windowSize)
            ],
            each [win]
        )
    in
        result
    • Dicken's avatar
      Dicken
      Post Prodigy

      Thaanks all, that's enough to be going on with i shall go through them all. 

  • let
        lst = {1..15},
        window = 3, 
        fx = (i, s) => if i = window 
            then List.Zip(s) 
            else @ fx(i + 1, {List.Repeat({null}, i) & List.RemoveLastN(lst, i)} & s)
    in
        fx(0, {})
  • Hi
    Another solution

    = List.Transform(
    {1..List.Count(alist)},
    (i)=> List.Transform(
    List.Numbers(List.Max({0, i-window}), window),
    each alist{_}))


    Stéphane