Forum Discussion

Iamnvt's avatar
Iamnvt
Continued Contributor
7 years ago
Solved

Combining Common value

Hello,

I have a field, which contains several values as below:

A, B
D, E, F
A, C
B, C
D, E, G



How can I group them together into a common group? Result as below:

A, B, C
D, E, F, G
A, B, C
A, B, C
D, E, F, G

 

ImkeF  please take a look. I think this has to use a custom loop function, but I dont know how

  • Hi Iamnvt,

    if you have many values on one row, split them into pairs and apply the code for relation pairs as suggested earlier.

     

    This code splits many values on a row into pairs. For example: A,B,C => {{A,B}, {B,C}}

     

    let
        Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WctRRcNJRcFaK1YlWAjF0FFx1FNzAXCDbBcxwAQqCGXApXx0FP5hUlFJsLAA=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [Column1 = _t]),
        Pairs = Table.AddColumn(
            Source, 
            "Pairs", 
            (row) =>
                let
                    lst =Text.Split(row[Column1], ", "),
                    lstToPairs = List.Accumulate(
                        lst,
                        [lastElement = null, resultList = {}],
                        (state, current) => 
                            if state[lastElement] = null then
                                [
                                    lastElement = current, 
                                    resultList = {}
                                ]
                            else
                                [
                                    lastElement = current, 
                                    resultList = List.Combine(
                                        {
                                            state[resultList], 
                                            {
                                                [
                                                    First = state[lastElement], 
                                                    Second = current
                                                ]
                                            }
                                        }
                                    )
                                ]
                    )
                in
                    lstToPairs
        ),
        #"Expanded Pairs" = Table.ExpandRecordColumn(Pairs, "Pairs", {"resultList"}, {"Pairs.resultList"}),
        #"Expanded Pairs.resultList" = Table.ExpandListColumn(#"Expanded Pairs", "Pairs.resultList"),
        #"Expanded Pairs.resultList1" = Table.ExpandRecordColumn(#"Expanded Pairs.resultList", "Pairs.resultList", {"First", "Second"})
    in
        #"Expanded Pairs.resultList1"

     

  • Nolock  this gives the expected result!.

     

    Just for further understanding, I am thinking for solution you gave at the first place, if I repeat the code for the "SomethingInCommon" column, it also gives me the result;

    How can I make the code recursive with while loop until no further transformation of the value in the row?

     

    let
        Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WctRRcNJRcNZRcFGK1YlWArHBDLiIi46CK5jhqqPgphQbCwA=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [Column1 = _t]),
        // split text into a list of values
        TempValueAsList = Table.AddColumn(Source, "TempValueAsList", each Text.Split([Column1], ", ")),
        // create new a column with all rows' values in common
        SomethingInCommon = Table.AddColumn(
            TempValueAsList, 
            "SomethingInCommon", 
            (curRow) => 
                let
                    // get all rows containing any of elements of the current record
                    tableWithSameElements = Table.SelectRows(TempValueAsList, (nestedRow) => List.ContainsAny(curRow[TempValueAsList], nestedRow[TempValueAsList])),
                    // get the column TempValueAsList
                    listToUnion = tableWithSameElements[TempValueAsList],
                    // union and sort all elements
                    resultList = List.Sort(List.Union(listToUnion)),
                    // convert the result list to a text
                    resultAsText = Text.Combine(resultList, ",")
                in
                    resultAsText
        ),
        // remove temp column
        RemoveTempColumn = Table.RemoveColumns(SomethingInCommon, {"TempValueAsList"}),
        TempValueAsList2 = Table.AddColumn(RemoveTempColumn, "TempValueAsList2", each Text.Split([SomethingInCommon], ",")),
        // create new a column with all rows' values in common
        SomethingInCommon2 = Table.AddColumn(
            TempValueAsList2, 
            "SomethingInCommon2", 
            (curRow) => 
                let
                    // get all rows containing any of elements of the current record
                    tableWithSameElements = Table.SelectRows(TempValueAsList2, (nestedRow) => List.ContainsAny(curRow[TempValueAsList2], nestedRow[TempValueAsList2])),
                    // get the column TempValueAsList
                    listToUnion = tableWithSameElements[TempValueAsList2],
                    // union and sort all elements
                    resultList = List.Sort(List.Union(listToUnion)),
                    // convert the result list to a text
                    resultAsText = Text.Combine(resultList, ",")
                in
                    resultAsText
        ),
        // remove temp column
        RemoveTempColumn2 = Table.RemoveColumns(SomethingInCommon2, {"TempValueAsList2"})
    in
        RemoveTempColumn2

12 Replies

  • Nolock's avatar
    Nolock
    Resident Rockstar

    Hi Iamnvt,

    I have a solution for you - the code is commented and contains also some sample data. If you have any questions, don't hesitate to ask :)

     

    let
        Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WctRRcFKK1YlWctFRcNVRcAOzgYLOYIYTjAGRdVeKjQUA", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [Column1 = _t]),
        // split text into a list of values
        TempValueAsList = Table.AddColumn(Source, "TempValueAsList", each Text.Split([Column1], ", ")),
        // create new a column with all rows' values in common
        SomethingInCommon = Table.AddColumn(
            TempValueAsList, 
            "SomethingInCommon", 
            (curRow) => 
                let
                    // get all rows containing any of elements of the current record
                    tableWithSameElements = Table.SelectRows(TempValueAsList, (nestedRow) => List.ContainsAny(curRow[TempValueAsList], nestedRow[TempValueAsList])),
                    // get the column TempValueAsList
                    listToUnion = tableWithSameElements[TempValueAsList],
                    // union and sort all elements
                    resultList = List.Sort(List.Union(listToUnion)),
                    // convert the result list to a text
                    resultAsText = Text.Combine(resultList, ",")
                in
                    resultAsText
        ),
        // remove temp column
        RemoveTempColumn = Table.RemoveColumns(SomethingInCommon, {"TempValueAsList"})
    in
        RemoveTempColumn

    And a screenshot of the result.

    • Iamnvt's avatar
      Iamnvt
      Continued Contributor

      Nolock  absolutely brilliant!

      I have a bit more complex scenarios:

       

      Column1SomethingInCommon

      A, BA,B,C,D,E,F
      B, CA,B,C,D,E,F
      C, DA,B,C,D,E,F
      D, EA,B,C,D,E,F
      E, FA,B,C,D,E,F

       

      it has a bridge between A,B and B,C and C, D --> B,C is the bridge --> result should be A,B,C,D

       

      How can I achieve that? 

      Thank you very much for the above solution; it already helped me a lot.

      • Nolock's avatar
        Nolock
        Resident Rockstar

        Hi Iamnvt,

        if I understand you well you would like to find a transitive closure. Am I right?