Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Calling all Data Engineers! Fabric Data Engineer (Exam DP-700) live sessions are back! Starting October 16th. Sign up.

Reply
Anonymous
Not applicable

I need to verify if one column contain similar string to another string

 

For example

 

The data fromStyle colourway from table1

code2 table2

code3 table3

code4 table4

 

style colourway  code2         code3          code4      code5                results

Baltic Sea/Clay   Cast Iron  Acid Yellow  Deep Navy    Bright Blue      "no data founded

Baltic Sea/Clay   Cast Iron  Acid Yellow  Deep Navy    Clay                  data contain Clay Capture2.PNG"

Thanks so much for your help

Javier

 

 

 

6 REPLIES 6
Jimmy801
Community Champion
Community Champion

Hello @Anonymous 

 

to provide you a good dynamic solution (if it's even needed) the requirement is not specified good enough. Here some questions

- the code-columns are always like this code2-code 5 or can there be more?

- what should be the result of something like this: Style: Deep blue- code4= blue?

 

Jimmy

Anonymous
Not applicable

- the code-columns are always like this code2-code 5 or can there be more?

always code2-code 5.

- what should be the result of something like this: Style: Deep blue- code4= blue?

Yes

Hello @Anonymous 

 

so you don't need any dynamic or more advanced comparings. So you can just go with the solution proposed by @dax and adapt the data source of course 🙂

 

All the best

 

Jimmy

Anonymous
Not applicable

Hi all,

 

Thank you for an interesting topic to think on :). It gave me an opportunity to test writing a custom function that takes other functions as arguments, it was quite fun :).

 

This is my version of the ContansEx. It takes three parameters:

1. Required. List of arguments. This can be either:

   a. {record, name_of_column_name_to_search_in, {list_of_column_name(s)_to_search_for}}

   b. {text_to_search_in, {list_of_text(s)_to_search_for}}

 the last parameter in both cases can be a list with only one paramter.

2. Optiona. Comparer function. Takes two text parameters: text_to_search_in and text_to_search_for evaluated dynamically based on the content of #1. Defaults to (x,y)=>Text.Contains(x,y), but can be overloaded with (e.g.) a reversed version (x,y)=>not Text.Contains(x,y) or something even more fancy.

3. Optional. Output fuction. Takes two parametes, which depends on type of the parameters passed in #1:

   a. in case of record: record (pased in #1) and current value of the column_name_to_search_for (as text!)

   b. in case of list: text_to_search_in and a current value of text_to_search_for.

 

Output, in any case, a list of values defined by the output function or containing an error message.

The is some error checking/handling in the function, but this can be improved.

 

This is the function itself (it looks quite lengthy, but you do not have to modify it, just copy and paste):

(parameters as list, optional fComparer as function, optional fOutput as function)=>
let 
    mComparer = if fComparer = null then (x, y)=> Text.Contains(x, y) else fComparer,
        
    // Assuming following logic:
    // 3 parameters used when search done in a record:
    //   1st parameter - the record
    //   2nd parameter - name of the field to search in
    //   3rd parameter - name of the fields containing text to search for
    // 2 parameters used when searching in a text from list of values:
    //   1st parameter - text to search in
    //   2nd parameter - list of texts to search for

    InputType = if List.Count(parameters) = 2 then "list" else 
                    if List.Count(parameters) = 3 then "record" else "unknown",

    mOutput = if fOutput = null 
                then 
                    if InputType = "list" then (l as list, i as number)=> l{i}
                    else if InputType = "record"  then (r, fname)=> Record.Field(r, fname) 
                    else (x, y)=> "input parameters do not match any of funciton templates"
                else fOutput, 
    
    forList = 
        let 
            SearchIn = parameters{0},
            SearchFor = parameters{1},
            
            Processing = List.Accumulate(SearchFor, {}, (a, n)=> a & {if mComparer(SearchIn, n) then mOutput(SearchFor, List.PositionOf(SearchFor, n)) else null}),
            
           Output = if Value.Type(SearchIn) <> type text then {"SearchIn parameters should be text"} else
                        if  Value.Type(SearchFor) <> type list then {"SearchFor parameter should be list"}
                        else Processing
        in Output,
    
    forRecord = 
        let 
            mRecord = parameters{0},
            SearchIn = parameters{1},
            SearchFor = parameters{2},
            
            Processing = List.Accumulate(SearchFor, {}, (a, n)=> a & {
                    if mComparer(Record.Field(mRecord, SearchIn), Record.Field(mRecord, n)) 
                        then mOutput(mRecord, n) else null}),
            
            Output = if Value.Type(SearchIn) <> type text then {"SearchIn parameters should be text"} 
                        else if  Value.Type(SearchFor) <> type list then {"SearchFor parameter should be list"}
                        //else if Value.Type(mRecord) <> Record.Type then {Value.Type(mRecord)}
                        else Processing
        in Output,


    Output = if InputType = "list" then forList 
                else if InputType = "record" then forRecord
                else {"incorrect number of members in the list/first parameter"}
in
    Output

 

This is how this can be called (please note that the last two parameters can be omitted, I use it below only to demonstrate how the default behaviour can be overloaded):

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WSkxKTlHSUUoE4iQgBrFTgThNKVYnWqmwPLWopBLILQTiciAuBeIiMD82FgA=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [Column1 = _t, Column2 = _t, Column3 = _t, Column4 = _t, Column5 = _t, Column6 = _t]),
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"Column1", type text}, {"Column2", type text}, {"Column3", type text}, {"Column4", type text}, {"Column5", type text}, {"Column6", type text}}),
    ListUsingReversedSearch = Table.AddColumn(#"Changed Type", "Custom", each ContansEx({[Column1], {[Column2], [Column3],[Column4],[Column5], [Column6]}}, (a,b)=> not Text.Contains(a,b), (a, b)=> b )),
    RecordWithOverloadedOutput = Table.AddColumn(#"Changed Type", "Custom", each ContansEx({_, "Column1", {"Column2", "Column3", "Column4", "Column5", "Column6"}}, null, (a, b)=> {b, List.PositionOf(Record.FieldNames(a),b) } ))
in
    RecordWithOverloadedOutput

 

Kind regards,

JB

dax
Community Support
Community Support

Hi @Anonymous , 

You could try below M code to see whether it work or not

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WckrMKclMVghOTdR3zkmsVNJRck4sLlHwLMrPUwByHJMzUxQiU3Ny8suBPJfU1AIFv8QykDKnosz0jBIFp5zSVKVYHQoMAqsGm5CZnapfXg6SBzHxagIpi40FAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [#"style colourway" = _t, Code1 = _t, Code2 = _t, Code3 = _t, Code4 = _t]),
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"style colourway", type text}, {"Code1", type text}, {"Code2", type text}, {"Code3", type text}, {"Code4", type text}}),
    #"Added Custom" = Table.AddColumn(#"Changed Type", "c1", each if Text.Contains([style colourway],[Code1]) then [Code1]&"," else ""),
    #"Added Custom1" = Table.AddColumn(#"Added Custom", "c2", each if Text.Contains([style colourway],[Code2]) then [Code2] &","else ""),
    #"Added Custom2" = Table.AddColumn(#"Added Custom1", "C3", each if Text.Contains([style colourway],[Code3]) then [Code3]&"," else ""),
    #"Added Custom3" = Table.AddColumn(#"Added Custom2", "c4", each if Text.Contains([style colourway],[Code4]) then [Code4]&"," else ""),
    #"Merged Columns" = Table.CombineColumns(#"Added Custom3",{"c1", "c2", "C3", "c4"},Combiner.CombineTextByDelimiter("", QuoteStyle.None),"Merged"),
    Custom1 = Table.ReplaceValue(#"Merged Columns",each [Merged], each if [Merged]="" then "no found data" else "data contains  " & [Merged], Replacer.ReplaceValue, {"Merged"})
in
    Custom1

Best Regards,
Zoe Zhi

If this post helps, then please consider Accept it as the solution to help the other members find it more quickly.

Anonymous
Not applicable

Hi Zoe

 

Doesn't work look like tha table is static..

 

Thanks

Javier

Helpful resources

Announcements
FabCon Global Hackathon Carousel

FabCon Global Hackathon

Join the Fabric FabCon Global Hackathon—running virtually through Nov 3. Open to all skill levels. $10,000 in prizes!

October Power BI Update Carousel

Power BI Monthly Update - October 2025

Check out the October 2025 Power BI update to learn about new features.

FabCon Atlanta 2026 carousel

FabCon Atlanta 2026

Join us at FabCon Atlanta, March 16-20, for the ultimate Fabric, Power BI, AI and SQL community-led event. Save $200 with code FABCOMM.

Top Kudoed Authors