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

Get Fabric Certified for FREE during Fabric Data Days. Don't miss your chance! Learn more

Reply
OliverSch
New Member

Transforming List Columns for Power BI Reporting

Screenshot 2025-09-03 160857.pngHallo together,

 

In my Power BI report, I have a column that contains 'List' values (as seen in Power Query Editor). I want to represent the contents of these lists as a single, concatenated value within a visual. What is the recommended approach for this transformation?

Have anybody an idea how I can do that?

 

Thanks for your help.

 

Greetings

 

Oliver

 

1 ACCEPTED SOLUTION
MarkLaf
Super User
Super User

Best practice depends on what you want in your report. Do you want a static combo of the list items? Or do you want to be able to slice by the list items (via a more dynamic M:M relationship)?

 

If you want both, you basically follow the (more complex) M:M model and then also do the list concatenation via whatever flavor makes the most sense in your situation: Power Query similar to outline below for static combo, calculated column after loading to semantic model (this is generally less optimal than Power Query), or you could get through a measure (best choice if the concatenation needs to be dynamic / responsive to certain filters, otherwise Power Query is the better choice, probably).

 

A simple example to highlight the decision.

 

Given this simple table:

#table( 
    type table [Id = Int64.Type, List = {text}], 
    {
        {1,{"A","B","C"}},
        {2,{"D","E","F"}}
    } 
)

MarkLaf_0-1756958777491.png

 

An static combo would look like:

let
    Source = 
    #table( 
        type table [Id = Int64.Type, List = {text}], 
        {
            {1,{"A","B","C"}},
            {2,{"D","E","F"}}
        } 
    ),
    CombineListItems = 
    Table.TransformColumns(
        Source, 
        {"List", each Text.Combine(_, ","), type text}
    )
in
    CombineListItems

MarkLaf_1-1756959312855.png

 

And in your report, a slicer on List would look like:

MarkLaf_2-1756959519022.png

 

In other words, not useful as a slicer for most use cases, but if all you need is to display the concatenated list items as a static attribute, this is the way to go. This applies whether you are doing a conatenation of simple list items (as we are in this example) or otherwise expanding/unwrapping horizontally (i.e. not adding any rows as part of the transformation).

 

A more dynamic (M:M) setup would entail three tables - your original dimension, a new dimension constructed from all the list items in your List column, and a bridge with key pairs from the two dimensions:

 

Original

let
    Source = 
    #table( 
        type table [Id = Int64.Type, List = {text}], 
        {
            {1,{"A","B","C"}},
            {2,{"D","E","F"}}
        } 
    ),
    Select = Table.SelectColumns(Source,{"Id"})
in
    Select

 

List Dimension

let
    Source = 
    #table( 
        type table [Id = Int64.Type, List = {text}], 
        {
            {1,{"A","B","C"}},
            {2,{"D","E","F"}}
        } 
    ),
    Select = Table.SelectColumns(Source,{"List"}),
    ExpandListItems = Table.ExpandListColumn(Select, "List"),
    Distinct = Table.Distinct(ExpandListItems)
in
    Distinct

 

Bridge

let
    Source = 
    #table( 
        type table [Id = Int64.Type, List = {text}], 
        {
            {1,{"A","B","C"}},
            {2,{"D","E","F"}}
        } 
    ),
    ExpandListItems = Table.ExpandListColumn(Source, "List"),
    Distinct = Table.Distinct(ExpandListItems)
in
    Distinct

 

MarkLaf_4-1756961582542.png

 

Now, with this setup, we have dimensions (Original and now also List Dimension) that will work in slicers. One caveat, is that a slicer filter is needed to enforce filtering from many to one (one to many filters apply automatically). For example, for Original to filter List Dimension, Original automatically passes filters to Bridge (as this is one to many), but for bridge to then pass that filter to List Dimension (many to one), we need to explicitly call this out with a measure filter. Quick snip showing this:

 

MarkLaf_5-1756964810902.gif

 

DAX of slicer filters for reference:

Slice by Original = CALCULATE( IF( NOT ISEMPTY( Original ), 1 ), Bridge )
Slice by List Dim = CALCULATE( IF( NOT ISEMPTY( 'List Dimension' ), 1 ), Bridge )

 

View solution in original post

10 REPLIES 10
dufoq3
Super User
Super User

Hi @OliverSch, another solution:

Before

dufoq3_0-1758725194929.png


After

dufoq3_1-1758725213540.png

 

Add this code as a new step (replace "Source" if necessary):

= Table.TransformColumns(Source, {}, each if _ is list then Text.Combine(List.Transform(_, Text.From), "|") else _)


Whole code with sample data:

let
    Source = #table(null, {
    {"a", {"text1", "text2", "text3"}, "b", {1,2,3,4,5}},
    {"a", {"text4", "text5", "text6", "text7"}, "b", {10,20}} }),
    Custom1 = Table.TransformColumns(Source, {}, each if _ is list then Text.Combine(List.Transform(_, Text.From), "|") else _)
in
    Custom1

Note: Check this link to learn how to use my query.
Check this link if you don't know how to provide sample data.

v-sshirivolu
Community Support
Community Support

Hi @OliverSch ,

You can work with list columns in Power Query in several ways, depending on your reporting needs :

Convert a list to a text string for display or export:

Table.TransformColumns(
    YourTable,
    {
        "YourListColumn",
        each Text.Combine(List.Transform(_, Text.From), ","),
        type text
    }
)

This will change { "A", "B", "C" } to "A,B,C".


Expand the list into multiple rows for modeling or slicers:

Table.ExpandListColumn(YourTable, "YourListColumn")

This approach is best for filtering and relationships.


For both display and filtering:

Set up a many-to-many model by keeping your main table, creating a bridge table with the key and list items, and a dimension table of unique items, then relate them.


To handle multiple list columns automatically:

let
  listColumns = List.Select(
    Table.ColumnNames(YourTable),
    each Value.Is(Record.Field(YourTable{0}, _), type list)
  ),
  transformedTable = List.Accumulate(
    listColumns,
    YourTable,
    (state, current) =>
      Table.TransformColumns(
        state,
        {
          current,
          each Text.Combine(List.Transform(_, Text.From), ","),
          type text
        }
      )
  )
in
  transformedTable

This will convert all list-type columns to concatenated text.

If your lists contain records and you need a specific field:

Table.TransformColumns(
  #"Previous Step",
  {
    "YourListColumn",
    each if _ is list
         then Text.Combine(
                List.Transform(
                  List.RemoveNulls(_),
                  each Text.From(Record.Field(_, "lookupValue"))
                ),
                ", "
              )
         else 
    type text
  }
)

This extracts a chosen field (like "lookupValue") from each record in the list.

Hi @OliverSch ,
I hope the information provided above assists you in resolving the issue. If you have any additional questions or concerns, please do not hesitate to contact us. We are here to support you and will be happy to help with any further assistance you may need.

 

Hi @OliverSch ,

I hope the above details help you fix the issue. If you still have any questions or need more help, feel free to reach out. We’re always here to support you

 

 

Hi @OliverSch ,
I wanted to check if you had the opportunity to review the information provided. Please feel free to contact us if you have any further questions

MarkLaf
Super User
Super User

Best practice depends on what you want in your report. Do you want a static combo of the list items? Or do you want to be able to slice by the list items (via a more dynamic M:M relationship)?

 

If you want both, you basically follow the (more complex) M:M model and then also do the list concatenation via whatever flavor makes the most sense in your situation: Power Query similar to outline below for static combo, calculated column after loading to semantic model (this is generally less optimal than Power Query), or you could get through a measure (best choice if the concatenation needs to be dynamic / responsive to certain filters, otherwise Power Query is the better choice, probably).

 

A simple example to highlight the decision.

 

Given this simple table:

#table( 
    type table [Id = Int64.Type, List = {text}], 
    {
        {1,{"A","B","C"}},
        {2,{"D","E","F"}}
    } 
)

MarkLaf_0-1756958777491.png

 

An static combo would look like:

let
    Source = 
    #table( 
        type table [Id = Int64.Type, List = {text}], 
        {
            {1,{"A","B","C"}},
            {2,{"D","E","F"}}
        } 
    ),
    CombineListItems = 
    Table.TransformColumns(
        Source, 
        {"List", each Text.Combine(_, ","), type text}
    )
in
    CombineListItems

MarkLaf_1-1756959312855.png

 

And in your report, a slicer on List would look like:

MarkLaf_2-1756959519022.png

 

In other words, not useful as a slicer for most use cases, but if all you need is to display the concatenated list items as a static attribute, this is the way to go. This applies whether you are doing a conatenation of simple list items (as we are in this example) or otherwise expanding/unwrapping horizontally (i.e. not adding any rows as part of the transformation).

 

A more dynamic (M:M) setup would entail three tables - your original dimension, a new dimension constructed from all the list items in your List column, and a bridge with key pairs from the two dimensions:

 

Original

let
    Source = 
    #table( 
        type table [Id = Int64.Type, List = {text}], 
        {
            {1,{"A","B","C"}},
            {2,{"D","E","F"}}
        } 
    ),
    Select = Table.SelectColumns(Source,{"Id"})
in
    Select

 

List Dimension

let
    Source = 
    #table( 
        type table [Id = Int64.Type, List = {text}], 
        {
            {1,{"A","B","C"}},
            {2,{"D","E","F"}}
        } 
    ),
    Select = Table.SelectColumns(Source,{"List"}),
    ExpandListItems = Table.ExpandListColumn(Select, "List"),
    Distinct = Table.Distinct(ExpandListItems)
in
    Distinct

 

Bridge

let
    Source = 
    #table( 
        type table [Id = Int64.Type, List = {text}], 
        {
            {1,{"A","B","C"}},
            {2,{"D","E","F"}}
        } 
    ),
    ExpandListItems = Table.ExpandListColumn(Source, "List"),
    Distinct = Table.Distinct(ExpandListItems)
in
    Distinct

 

MarkLaf_4-1756961582542.png

 

Now, with this setup, we have dimensions (Original and now also List Dimension) that will work in slicers. One caveat, is that a slicer filter is needed to enforce filtering from many to one (one to many filters apply automatically). For example, for Original to filter List Dimension, Original automatically passes filters to Bridge (as this is one to many), but for bridge to then pass that filter to List Dimension (many to one), we need to explicitly call this out with a measure filter. Quick snip showing this:

 

MarkLaf_5-1756964810902.gif

 

DAX of slicer filters for reference:

Slice by Original = CALCULATE( IF( NOT ISEMPTY( Original ), 1 ), Bridge )
Slice by List Dim = CALCULATE( IF( NOT ISEMPTY( 'List Dimension' ), 1 ), Bridge )

 

Omid_Motamedise
Super User
Super User

A list might include more than one value. What is your preferred aggregation operation to summarize them into a single value?


If my answer helped solve your issue, please consider marking it as the accepted solution.
anilgavhane
Resolver IV
Resolver IV

@OliverSch

If you’d like help transforming list columns in Power Query for Power BI, here’s a streamlined guide:

 

Transforming List Columns in Power Query

1. Convert List to Text

To turn a list like { "A", "B", "C" } into "A, B, C":

 

Table.TransformColumns( YourTable, {{"YourListColumn", each Text.Combine(List.Transform(_, Text.From), ","), type text}} )

 

 

This is useful for display purposes or when exporting to visuals that expect text.

 

2. Expand List into Rows

If each list item should become its own row:

 

Table.ExpandListColumn(YourTable, "YourListColumn")

 

This is ideal for one-to-many relationships, like tags or categories.

 

3. Expand List into Columns

If the list has a fixed number of items and you want each item in its own column:

 

  • Convert the list to text:

     

     

     

    Text.Combine(List.Transform(_, Text.From), ",")

     

    1. Then split it:

       

      Table.SplitColumn( YourTable, "YourListColumn", Splitter.SplitTextByDelimiter(","), {"Item1", "Item2", "Item3"} )

       

       

      4. Dynamic Handling of Multiple List Columns

      To process all list-type columns dynamically:

       

      let listColumns = List.Select( Table.ColumnNames(YourTable), each Value.Is(Record.Field(YourTable{0}, _), type list) ), transformedTable = List.Accumulate( listColumns, YourTable, (state, current) => Table.TransformColumns( state, {{current, each Text.Combine(List.Transform(_, Text.From), ","), type text}} ) ) in transformedTable

       

      This automatically finds and transforms all list columns to text.

AmiraBedh
Super User
Super User

Hello !

You can add a custom column in PQ and convert the list to text:

= let
    items = List.RemoveNulls([Tabelle]),        
    txt   = if List.IsEmpty(items) 
            then null 
            else Text.Combine(List.Transform(items, each Text.From(_)), ", ")
in
    txt

If the list contains records, extract a field first:

= let
    items = List.Transform([Tabelle], each Record.Field(_, "lookupValue")),
    items2 = List.RemoveNulls(items)
  in
    if List.IsEmpty(items2) then null else Text.Combine(List.Transform(items2, Text.From), ", ")

Then you convert the column in place:

= Table.TransformColumns(#"Previous Step",
    {{"Tabelle", each if _ is list 
       then Text.Combine(List.Transform(List.RemoveNulls(_), Text.From), ", ")
       else _, type text}})

 


Proud to be a Power BI Super User !

Microsoft Community : https://docs.microsoft.com/en-us/users/AmiraBedhiafi
Linkedin : https://www.linkedin.com/in/amira-bedhiafi/
StackOverflow : https://stackoverflow.com/users/9517769/amira-bedhiafi
C-Sharp Corner : https://www.c-sharpcorner.com/members/amira-bedhiafi
Power BI Community :https://community.powerbi.com/t5/user/viewprofilepage/user-id/332696
MasonMA
Community Champion
Community Champion

@OliverSch 

 

I would suggest using 'Expand to New Rows' so that each list item becomes a row. (If concatenated, it’s just a string and you lose the ability to slice/filter on individuals)

 

This gives you a normalized fact-style table, which works nicely with DAX measures, slicers, and relationships.

 

From UI

MasonMA_0-1756910353857.png

Or M with Table.ExpandListColumn(Source, "Column")

 

Helpful resources

Announcements
Fabric Data Days Carousel

Fabric Data Days

Advance your Data & AI career with 50 days of live learning, contests, hands-on challenges, study groups & certifications and more!

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.