Forum Discussion

informer's avatar
informer
Helper I
1 year ago
Solved

Power Query - Table.ReplaceValue - Behavior ?

Hi,

 

My question is very basic and is about the behavior of Table.ReplaceValue. Below a table in PWQ

 

incomekindhometeenhome

5011

00
460011
700000
260011
580010
630001
556701
333311

 

I d'ont understant the two different results between

 

= Table.ReplaceValue(  #"Typage", each [kidhome], each 2, 
  Replacer.ReplaceValue,
  {"kidhome", "teenhome"})

 

and

 

= Table.ReplaceValue(  #"Typage",   each [kidhome],   each 2, 
  (curval,oldval, newval)=> newval,
  {"kidhome", "teenhome"})

 

 

 

Subsidiary question

 

Table.ReplaceValue(
   table as table,
   oldValue as any,
   newValue as any,
   replacer as function,
   columnsToSearch as list,
) as table

 

Why a personal replacer function is declared why 3 parameters mandatory (x,y,z) => ?

How each parameter is well associated with the 3 first parameters of Table.ReplaceValue ?

 

Thanks by advance for your help ?

  • slorin's avatar
    slorin
    1 year ago

    informer 

    Sur les points 1 et 3

    quand vous ajoutez une colonne à une table, vous ne vous demandez pas ce que veut dire le [xxxx]

    exemple, si vous créez une nouvelle colonne avec les 2 derniers caractères d'une autre colonne 

    = Table.AddColumn(Source, "Column2", each Text.End([Column1], 2), type text)

    le [Column1] désigne le texte contenu dans le champ intitulé "Column1" de votre ligne en cours

    cela vous semble naturel !

     

    vous pourriez également écrire : 

    = Table.AddColumn(Source, "Column2", (_) => Text.End(_[Column1], 2), type text)

    ici j'ai mis un _ mais vous auriez pu mettre un x ou informer

     

    cette syntaxe est valable

    = Table.AddColumn(Source, "Column2", (informer) => Text.End(informer[Column1], 2), type text)

     il est implicite que "informer" est l'enregistrement en cours (de l'étape "source")

     

    La fonction Table.ReplaceValue est plus complexe car la fonction du 4e argument utilise les 3 arguments précédents pour elle-même. quelque soit les noms qu'on leur donne (x,y,z) ou (a,b,c) ou (informer1,informer2,informer3)

     

    = Table.ReplaceValue(Source, Argument2, Argument3, (informer1,informer2,informer3)=>informer2, {"Column1"}

     ici on remplacera la column1 par le valeur du 2e argument

    ce peut être du texte, un nombre, une liste... lié à la ligne en cours si on a un each...

    mais également une valeur d'une autre requête

     

    un exemple tiré par les cheveux pour bien comprendre, 

     

    let
    Source = Table.FromColumns({{1..3}},{"Column1"}),
    Replace = Table.ReplaceValue(Source, Source[Column1], (toto)=> Source , (a,b,c)=>a, {"Column1"})
    in
    Replace

    ne changera rien à la column1, on prend la valeur du premier argument (donc la column1) et on le remet.

     

    let
    Source = Table.FromColumns({{1..3}},{"Column1"}),
    Replace = Table.ReplaceValue(Source, Source[Column1], (toto)=> Source , (a,b,c)=>b, {"Column1"})
    in
    Replace

    on n'a pas de each, on n'est donc pas dans la ligne en cours, on prendre la colonne "Column1" de la table "Source" c'est à dire la colonne elle-même (en entier !) 

    on aura donc une liste {1..3} dans chaque cellule.  

     

    enfin, 

    let
    Source = Table.FromColumns({{1..3}},{"Column1"}),
    Replace = Table.ReplaceValue(Source, Source[Column1], (toto)=> Source , (a,b,c)=>c, {"Column1"})
    in
    Replace

    ici la fonction renvoie c, le 3eme argument que j'ai volontairement écrit (toto)=> (toto ou _ ou each, c'est la même chose, c'est la ligne en cours

    sauf que là, je ne renvoie pas un champ spécifique de la ligne avec des [  ] mais Source, donc l'étape précédente.

    Dans toutes les cellules j'aurais donc la table Source avec sa seule colonne de trois valeurs, 1, 2, 3.

     

     

    Quant au point 2, Power Query ne génère pas d'erreur lorsqu'il n'y a pas assez d'argument, mais les modifications ne sont pas effectuées
    Si par exemple j'écris : 

    = Table.ReplaceValue(Source, each null, each null , Date.Day, {"Column1"})

    Date.Day est une fonction avec un seul argument, je n'ai aucune erreur, mais la fonction ne remplace rien.

    = Table.ReplaceValue(Source, each null, each null , List.Accumulate, {"Column1"})

    pas d'erreur non plus avec List.Alternate qui demande pourtant 3 arguments. la fonction renvoie un erreur, il ne se passe rien. peut-être un bug de Power Query ?

     

    Est-ce plus clair ?

     

    Stéphane

     

     

     

     

25 Replies

  • informer lets start from your last questions:

    # 3 mandatory parameters for custom replacer: it's because Table.ReplaceValue passes all 3 to this function.

    # assiciations: look at any standard PQ replacer function definition:

    Replacer.ReplaceValue(value as any, old as any, new as any) as any

    Arguments' values are passed in the same order. So that 

    value : current value in one of columnsToSearch

    old: oldValue in Table.ReplaceValue

    new: newValue in Table.ReplaceValue

    Keeping the above in mind try to imagine what's going on in your use cases: column by column, row by row...

     

    • informer's avatar
      informer
      Helper I

      Thanks for your help

      The 4th parameter is a function

      I don't understant the 2nd exemple because it's a personal function and Replacer.ReplaceValue is never called

       

      (curval,oldval, newval)=> newval,

       

       

      In the example below, Replacer.ReplaceValue is not called

       

      = Table.ReplaceValue(
       Source, 
       each [Acronyme], 
       null, 
       (x,y,z) => 
          List.Accumulate(
            List.Reverse(Text.PositionOf(x, y, Occurrence.All, Comparer.OrdinalIgnoreCase)),
            x, 
            (s,c)=>Text.RemoveRange(s, c, Text.Length(y))),
       {"Nom", "Volume", "Circulating Supply"})

       

      In the Table.ReplaceValue, nothing is precised about parameters to pass in

      replacer as function,

       I'm sure I'm missing something about construction of a personal function !!!

      • AlienSx's avatar
        AlienSx
        Super User

        what's so special about Replacer.ReplaceValue? It's one of many other functions in M. You may use any other custom function with the same list of agruments. All you need to now is that Table.ReplaceValue passes exactly 3 values into it's 4th argument (the function we are talking about). By "passes" I mean that Table.ReplaceValue calls that function like we call any other function in M. Back to your examples: 

        1. The one with Replacer.ReplaceValue: full syntax of this "replacer" is 

        Replacer.ReplaceValue(value as any, old as any, new as any) as any

        and basically it compares value with old and if value = old then it replaces value with new. Your "old" argument always has a value of kidhome field. And when Table.ReplaceValue works with "kidhome" column then value is always equal to old. That's why kidhome column = 2 (as you defined new) after transformation. 

        When working with teenhome field, it's value will be replaced by 2 only when [teenhome] = [kidhome] (or when value = old). That's why replacements are made in rows 1 through 4 and 8. 

        2. The one with custom function: here your custom function always returns a value of new with is 2 in your case - without regard of any other values in any other column. That's why both column's values got replaced with 2.

         

        Table.ReplaceValue is not easy to understand and I feel your frustration. Good luck!

  • This is an interesting question. It seems that you are very interested in the second example.

     

    Before explaining this question, you should know that if a table function needs a function as a parameter, it usually passes the parameters in order, which I call implicit parameter passing. For example, the third parameter of the Table.AddColumn function needs to specify a function. During the execution of the Table.AddColumn function, it passes the table row (a record value) as a parameter to the third parameter (a function), and then calculates a result as the value of the new column.

     

    The same is true for the Table.ReplaceValue function, which implicitly passes the value of each row of the column specified in the fifth parameter, the second parameter, and the third parameter to the fourth parameter (a function).The fourth argument (a function) computes a result based on the three provided arguments, which is then used as the new value to replace the original value.

     

    In the second example, your result is a fixed value (newval), so it will always replace the original value in the table with newval(it corresponds to the third parameter).

    Here are some examples I learned before, maybe they can help you.

    Table.ReplaceValue(
        #table({"A", "B"}, {{1, 2}, {11, 11}, {101, 102}}), 
        11, 
        666, 
        Replacer.ReplaceValue, 
        {"A"}
    )
    
    Table.ReplaceValue(
        #table({"A", "B"}, {{1, "take"}, {11, "make"}, {111, "like"}}), 
        "ak", 
        "****", 
        Replacer.ReplaceText, 
        {"B"}
    )
    
    Table.ReplaceValue(
        #table({"A", "B"}, {{1, 2}, {11, 11}, {101, 102}}), 
        888, 
        666, 
        (x, y, z) => if x = 11 then y else z, 
    	{"A"}
    )
    
    Table.ReplaceValue(
        #table({"A", "B"}, {{1, 2}, {11, 11}, {101, 102}}), 
        null, 
        null, 
        (x, y, z) => if x = 11 then x * 100 else x / 100, 
        {"A"}
    )
    
    Table.ReplaceValue(
        #table({"A", "B"}, {{1, 2}, {11, 11}, {101, 102}}), 
        each [B], 
        666, 
        (x, y, z) => if y = 102 then 777 else x, 
        {"A"}
    )

     

    • AntrikshSharma's avatar
      AntrikshSharma
      Community Champion

      ZhangKun Greate examples! For the last example I believe you wanted to write:

       

      (x, y, z) => if y = 102 then z else x

      For those who might find x, y, z difficult to understand at first.

      Table.ReplaceValue (
          #table ( { "A", "B" }, { { 1, 2 }, { 11, 11 }, { 101, 102 } } ),
          each [B],
          666,
          ( CurrentValue, OldValue, NewValue ) =>
              if OldValue = 102 
              then NewValue 
              else CurrentValue,
          { "A" }
      )

       

       

      • ZhangKun's avatar
        ZhangKun
        Super User

        This is an example from a little back ago, and I was trying to say that the second and third parameters of Table.ReplaceValue do not necessarily have to be used in the fourth parameter.

  • Your second example has too many parameters. If you specify the replacer function then the 

    each [kidhome],   each 2

    part is ignored.

  • Anonymous's avatar
    Anonymous
    Not applicable

    Hi informer,

    Thanks for reaching out to the Microsoft fabric community forum.

     

    It looks like you are trying to use "Table.ReplaceValue" function but in two different ways. As ronrsnfldlbendlinslorin and ZhangKun provided with responses, were you able to solve your issue? If your issue is solved then kindly mark the helpful response as solution and if you still have queries left then kindly mention your primary queries.

     

    I would also take a moment to thank ZhangKun, lbendlin, AntrikshSharma and AlienSx, for actively participating in the community forum and for the solutions you’ve been sharing in the community forum. Your contributions make a real difference.

     

    If I misunderstand your needs or you still have problems on it, please feel free to let us know.  

    Best Regards,
    Hammad.
    Community Support Team

     

    If this post helps then please mark it as a solution, so that other members find it more quickly.

    Thank you.