Forum Discussion

pureswing's avatar
pureswing
Frequent Visitor
8 years ago
Solved

using M function, If text column CONTAINS specific value, then ...

Hi everyone, I've been learnig a lot about m functions and how to handle queries, cool stuff indeed  :)  But my knowledge does not solve this problem and I'm stuck, I would appreciate any help ple...
  • MarcelBeug's avatar
    8 years ago

    Well, that's a nice Christmas puzzle, thanks!

     

    Can't wait though:

     

    let
        Source = Table1,
    
        // Add Index as original sort so the result can be sorted back to the original sort:
        #"Added Index" = Table.AddIndexColumn(Source, "Index", 0, 1),
    
        // Split text by parentheses, so the part numbers will be the 2nd, 4th, 6th item in the nested lists:
        #"Splitted Text" = Table.AddColumn(#"Added Index","Parts", each Text.SplitAny([Description],"()"), type {text}),
    
        // Take alternate items (only the parts that were between parentheses:
        #"Alternate Items" = Table.TransformColumns(#"Splitted Text",{{"Parts", each List.Alternate(_,1,1,0), type {text}}}),
    
        // Expand the list column to new rows
        #"Expanded Parts" = Table.ExpandListColumn(#"Alternate Items", "Parts"),
    
        // Merge table with itself:
        #"Merged Queries" = Table.NestedJoin(#"Expanded Parts",{"Parts"},Table1,{"ID"},"Table1",JoinKind.LeftOuter),
    
        // Expand the Description, which wil be the replacements values:
        #"Expanded Table1" = Table.ExpandTableColumn(#"Merged Queries", "Table1", {"Description"}, {"Table1.Description"}),
    
        // Add parentheses to ensure that only parts between parentheses will be replaced:
        #"Added Parentheses" = Table.TransformColumns(#"Expanded Table1",{{"Parts", each "("&_&")", type text}, {"Table1.Description", each "("&_&")", type text}}),
    
        // Group to the original number of rows, with "Parts" and "Table1.Description" combined to a list of lists for replacements which looks like: {{old, new},{old, new}, etc.}:
        #"Grouped Rows" = Table.Group(#"Added Parentheses", {"ID", "Name", "Description", "Index"}, {{"Replacements", each Table.ToRows(Table.SelectColumns(Table.SelectRows(_,each [Table1.Description] <> null),{"Parts","Table1.Description"})), type list}}),
    
        // Replacements are done using List.Accumulate to loop over each item in [Replacements] (r) and replace old (r{0}) with new (r{1}) in [Description] (d):
        #"Added Solution Expected" = Table.AddColumn(#"Grouped Rows", "Solution Expected", each List.Accumulate([Replacements],[Description], (d,r) => Replacer.ReplaceText(d, r{0}, r{1}))),
    
        // Back to original sort:
        #"Sorted Rows" = Table.Sort(#"Added Solution Expected",{{"Index", Order.Ascending}}),
    
        // Remove temporary columns:
        #"Removed Columns" = Table.RemoveColumns(#"Sorted Rows",{"Index", "Replacements"})
    in
        #"Removed Columns"

     

    You might be interested in my Power Query (M) Functions Dashboard.

     

    Happy holidays!

  • MarcelBeug's avatar
    MarcelBeug
    8 years ago

    It's partly my fault. I stated that I was merging the table with itself, but I changed my mind - and the code - to merge the current query with Table1, which was another query that only imported (and typed) the table from Excel into Power Query.

     

    Probably you named your query "Table1", that's why you got the cyclic reference error, as you can't refer to a query from inside the same query.
    In case of 1 query, you can still reference the Source step as original table.

     

    So, the only correction required in your query is the #"Merged Queries1" step, which has 2 errors: the first column must be "Parts", not "ID" and the second table must be Source, as explained above.

     

       #"Merged Queries1" = Table.NestedJoin(#"Expanded Parts",{"Parts"},Source,{"ID"},"NewColumn",JoinKind.LeftOuter),