How to get values from a nested multi-link table?

Hi!

I am working in an application that uses several dat tables.
Table 1 links to another table with a multi link column to Table 2
Table2 links to another table with a multi link column to Table3
Table3 has column “name” and “value”

I’m trying to reach the list of values on Table3 from the first Table1 row, so I can calculate a maximum of all.
I am able to make the same in a column in Table2 but not in Table3. I get the error:
“TypeError: list indices must be integers or slices, not str”

I am accessing the information like this

  listofTable2 = Table1_Item['table2Link']
  liastofTable3 = [r['table3link'] for r in listofTable2]
  listofValues = [z['value'] for z in liastofTable3]
  max(listofValues)

I tried also to conver to adictionary, but no luck.
For sure I am missing something.

Any ideas, hints?

Thanks!

1 Like

Just having a cursory look here.

I can at least mention the following concerning multi-link columns and the error you are receiving:

“TypeError: list indices must be integers or slices, not str”

A multi-link column is basically a list. This means that when you are trying to access rows within a multi link column you have to use integers to index since it is a list.

For example:

# access values from a column that holds a single link to another table's row
my_row['single_link_column']['some_column_from_the_linked_table']

# access the first row that is linked in a multi-link column (notice the integer index)
my_row['multi_link_column'][0]['some_column_from_the_linked_table']

So, if you are using multi-links, you will have to loop through (or use the query operator) to return the list of linked rows. Please see the docs on DataTables.

Hi @alcampopiano, thanks a lot for you feedback.
I didn’t explain properly my issue.

I can get the list of items I want from Table2, from any of its columns. Table1 has a multi-link to Table 2.
If I do this for example, it works as expected:

list_of_Table2 = Table1_Item['table2_Link_column']
list_of_values = [r['values_column'] for r in list_of_Table2]
max(list_of_values)

I get a list accessing the column in Table1, then I loop the desired column in Table2. No problem here.

But when I try to access in the same way a multi-link column in Table2 linked with Table3, I get the error.
So if I do:

list_of_Table2 = Table1_Item['table2_Link_column']
list_of_Table3 = [r['table3_Link_column'] for r in list_of_Table2]
list_of_values = [r['values_column'] for r in list_of_Table3]
max(list_of_values)

I was expecting that when I perform this operation I get a list of Table3 rows:

list_of_Table3 = [r['table3_Link_column'] for r in list_of_Table2]

So I can iterate in the same way and access the column I want.

This is what I am stuck now.

Thanks!


table_1_row = <table_1_row>
table_2_rows = table_1_row['link_2'] = List[<table_2_row>]
[r['link_3'] for r in table_2_rows] = List[List[<table_3_row>]]

To flatten this list instead do

values = []
for table_2_row in table_1_row['link_2']:
  for table_3_row in table_2_row['link_3']:
    values.append(table_3_row['value'])

or equivalently with a list comprehension


values = [table_3_row['value']
            for table_2_row in table_1_row['link_2']
              for table_3_row in table_2_row['link_3']
         ]

And to do all table 3 rows :thinking::exploding_head:


values = [table_3_row['value']
          for table_1_row in app_tables.table_1.search()
            for table_2_row in table_1_row['link_2']
              for table_3_row in table_2_row['link_3']
         ]

It feels like inception…

2 Likes

Thanks a lot @stucork!
It worked out, with just one small modification, as the lists can be NoneType so we try to iterate through, we get an error.
I finally did as follows:

  values = []
  for table_2_row in table_1_row['link_2']:
    if table_2_row['link_3'] is not None:
      for table_3_row in table_2_row['link_3']:
        values.append(table_3_row['value'])
  print(max(values))  

I assume there is a more elegant way to check for empty lists, but it worked.

Yes, it looks like inception… the reason being is that the data structure I have works like a tree, I couldn’t flatten it more…

Thanks for the help!

1 Like

nice - the other thing you could do is make sure that when you add a row you always set the linked rows to an empty list if there are no links.

table_1_row = app_tables.table_1.add_row(link_2 = [])

thinks way you’ll never have NoneTypes as linked lists.

A function to do this would be something like

def make_links(app_table, linked_rows=None):
  linked_rows = linked_rows or []
  table_row = app_tables.get(app_table).add_row(linked_rows=linked_rows)

Or similar…


Edit: thanks @stefano.menci for spotting the mutable as a default. :man_facepalming:

Thanks a lot @stucork!
Yes, it is indeed a good practice.
I will implement it straight away.

Thanks again for your support!

Careful: using an empty list (or any mutable) as default value in the function argument could lead to sneaky bugs.

Try to google python empty list as argument and see the details.

The right way is to use None and then create an empty list inside the function:

def make_links(app_table, linked_rows=None):
  linked_rows = linked_rows or []
  table_row = app_tables.get(app_table).add_row(linked_rows=linked_rows)
1 Like

Thanks @stefano.menci I will have it in account!

1 Like