Forum Discussion

Dicken's avatar
Dicken
Icon for Post Prodigy rankPost Prodigy
4 months ago
Solved

List.Generate, make behave like Accumulate or XL REDUCE

Hi,
my staring point was this, i wanted to accumute fieds to a  record;  so i used; 

let
  f    = {List.Sum, List.Max, List.Average},
      head = {"sum", "max", "avg"},
      pos  = {0, 1, 2},
      val  = {2, 3, 1, 5, 2, 1}
    in
      List.Accumulate(pos, [], (s, c) => Record.AddField(s, head{c}, Function.Invoke(f{c}, {val})))

so simplifying you can have;

= let val = {12,21,34} , pos = {0,1,2}, 
head = {"a","b","c"}  
in List.Accumulate(  pos, [], (s,c)=> Record.AddField( s, head {c} , val {c} )) 

i have been trying to replaicate using generate; i have;  but this accumutes a  list of records, with the final being 
what is wnated.  is there a way to just generate each field , 

 let 
head = { "sum", "max", "avg"}, 
val = {2,3,1,5,2,1}
 in
  List.Generate(()=> [ x = 0, y = Record.AddField( [],head {0}, val{0} ) ],
                 each [x] < List.Count( head), 
                 each [x = [x] + 1, y = Record.AddField( [y], head {x} , val {x} ) ], 
each [y] )


i don't know if this is possible using Gen,  perhaps putting it insided a record [  x = y, z = Listgenerate ] ? 
any suggestions ? or as i think perhaps not doable ? 
just to note, if anyone dashes of a quick repsonse i may not be able to respond until tomorrow. 
Richard

  • and try this

    let 
    f    = {List.Sum,List.Max, List.Average},
    head = { "sum", "max", "avg"}, 
    val = {2,3,1,5,2,1},
    to=
      List.Generate(()=> [ i = 0, j = Record.AddField( [],head {i}, f{i}(val) )  ],
                     (x)=> x[i] <= List.Count( head)-1, 
                     (x)=> [i = x[i] + 1, j = Record.AddField( [],head {i},f{i}(val))
    ],
                     (x)=>x[j])
    in
      Record.Combine( to)

9 Replies

  • To get such a result, you need to use neither List.Accumulate nor List.Generate

    let
      f    = (x)=> {List.Sum(x), List.Max(x), List.Average(x)},
          head = {"sum", "max", "avg"},
          val  = {2, 3, 1, 5, 2, 1},
       to =     Record.FromList(f(val), head)
        in to

     

    • Dicken's avatar
      Dicken
      Icon for Post Prodigy rankPost Prodigy

      yes, i know , but i wanted to use LIst.Generate,  can it be done ? 

      • Ahmedx's avatar
        Ahmedx
        Icon for Super User rankSuper User

        pls try

        let
            f  = {List.Sum, List.Max, List.Average},
              head = {"sum", "max", "avg"},
              n = List.Count(head)-1,
              val  = {2, 3, 1, 5, 2, 1},
             to =  List.Generate(()=>[i=0, j=f{i}],
                       (x)=> x[i]<=n,
                       (x)=>[i= x[i]+1,j =f{i}],
                       (x)=> Function.Invoke(x[j],{val}))
        in
           Record.FromList(to,head)
  • and try this

    let 
    f    = {List.Sum,List.Max, List.Average},
    head = { "sum", "max", "avg"}, 
    val = {2,3,1,5,2,1},
    to=
      List.Generate(()=> [ i = 0, j = Record.AddField( [],head {i}, f{i}(val) )  ],
                     (x)=> x[i] <= List.Count( head)-1, 
                     (x)=> [i = x[i] + 1, j = Record.AddField( [],head {i},f{i}(val))
    ],
                     (x)=>x[j])
    in
      Record.Combine( to)

    • Dicken's avatar
      Dicken
      Icon for Post Prodigy rankPost Prodigy

      Thanks, will work through properly,  i like anythiing that invvolvves records 😊

      • Ahmedx's avatar
        Ahmedx
        Icon for Super User rankSuper User

         

        let
            f = {List.Sum, List.Max, List.Average},
            head = {"sum", "max", "avg"},
            val = {2, 3, 1, 5, 2, 1},
            to = List.Generate(
                () => 0, 
                (x) => x <= List.Count(f) - 1, 
                (x) => x + 1, 
                (x) => Record.FromList({f{x}(val)}, {head{x}})
            )
        in
            Record.Combine(to)
        ============================
        let
            f = {List.Sum, List.Max, List.Average},
            head = {"sum", "max", "avg"},
            val = {2, 3, 1, 5, 2, 1},
            
            to = List.Generate(
                () => 0, 
                (x) => x <= List.Count(f)-1, 
                (x) => x + 1,
                (x) =>  Record.AddField([],head {x}, f{x}(val) ))
        in
            Record.Combine(to)

  • You can use List.Generate, but it seems cumbersome when what you want to do is accumulate results into a single record as List.Accumulate can do. List.Generate returns a List by design.

    One method would be to wrap List.Generate inside List.Last

    let 
      val = {12,21,34} , 
      pos = {0,1,2}, 
      head = {"a","b","c"},
     
      res =  List.Last(List.Generate(
        ()=>[idx=0, x=Record.AddField([],head{idx},val{idx})],
        each [idx] < List.Count(head),
        each [idx=[idx]+1, x=Record.AddField([x],head{idx},val{idx})],
        each Record.Combine({[x]})))
    in
        res

     

    Another method would be to return a List of Records and then combine them into a single record:


    let 
      val = {12,21,34} , 
      pos = {0,1,2}, 
      head = {"a","b","c"},
     
      res = Record.Combine(List.Generate(
        ()=>[idx=0, x=Record.AddField([],head{idx},val{idx})],
        each [idx] < List.Count(head),
        each [idx=[idx]+1, x=Record.AddField([],head{idx},val{idx})],
        each [x]))
    in
        res

     

    Please note that the most efficient method (within your constraints) would be by using List.Accumulate. Theoretically, Record.Combine(List.Generate(...  should be more efficient than List.Last(List.Generate(... as one is only generating a single record for each "loop" in the former, and increasing numbers of records in the latter.

  • Please provide sample data that covers your issue or question completely, in a usable format (not as a screenshot).
    Do not include sensitive information. Do not include anything that is unrelated to the issue or question.
    Please show the expected outcome based on the sample data you provided.

    Need help uploading data? https://community.fabric.microsoft.com/t5/Community-Blog/How-to-provide-sample-data-in-the-Power-BI-Forum/ba-p/963216
    Want faster answers? https://community.fabric.microsoft.com/t5/Desktop/How-to-Get-Your-Question-Answered-Quickly/m-p/1447523

    • Dicken's avatar
      Dicken
      Icon for Post Prodigy rankPost Prodigy

      As far as i can tell there is no way to upload a copy of the file created, if there is could you plase let me know.