Flatten list with python

Me again :laughing:

I’m trying to flatten a list in python, I’ve tried it several ways:

Then I checked these forums and found this method but it doesn’t work for me:

I’m feeding in a list of points and I’d like the list flattened so the python looks like the List.Flatten node.

Traceback (most recent call last):
File “”, line 10, in
TypeError: Point is not iterable<< Was the error from the 2nd screenshot.

How do I do this?

Have you tried this ? https://stackoverflow.com/questions/2158395/flatten-an-irregular-list-of-lists

In your case, it should translate this way :

import collections

def flattenList(unflattened_list):
	if isinstance(unflattened_list,collections.Iterable):
		return [sub_element for element in unflattened_list for sub_element in flattenList(element)]
	else:
		return [unflattened_list]
OUT = flattenList(IN[0])

Edit : Worked for me outside of Dynamo :

4 Likes

Oooo… Thank you!

I’d done a work around (I am actually generating the list within the script so I flattened the first bit then added to it) but this is much nicer. :slight_smile:

It has some caveats (i.e. cannot be ran with numbers unless inside a real list), but this also works using List Comprehensions

lst = IN[0]

def flat(l):
    return [item for sublist in l for item in sublist]

OUT = flat(lst)

Or even just a List Comprehension itself

OUT = [item for sublist in IN[0] for item in sublist]

Traceback (most recent call last):
File “”, line 15, in
File “”, line 13, in flat
TypeError: iteration over non-sequence of type Point<<

Same warning error for the other one too.

I tried loads of variations of loops and stuff and none worked.
mellouze’s solution does though… If anyone has an explanation why I’d be interested as I’m obviously still a total noob.

I’ll try to explain both functions with words.

def flat(l):
    return [item for sublist in l for item in sublist]
  • Take l as entry (l is supposed to be a list)
  • Return a list constructed as such : An enumeration of all the item contained in all the sublist of l.

Here, each object named sublist is required to be an iterable (e.g. a list). If called, the function will try to iterate over each sublist item. In your case, you are feeding a list l that contains both points and lists of points. The function will successfully iterate on all the lists of points, but will return an error when it will try to iterate on the points (which is the error you quote in your last post).

def flattenList(l):
	if isinstance(l,collections.Iterable):
		return [item for sublist in l for item in flattenList(sublist)]
	else:
		return [l]

Here, the function is a bit more complex. (I changed the name of the variables to match the one of the previous function)

  • Given a variable l, the function will first check if it is an instance of collections.Iterable, which essentially dictates if Python will be able to iterate over it.
  • If the object l is an iterable (meaning that in our case, it is a list), the function will return something similar to @solamour’s function. However, Python will not iterate over sublist but over flattenList(sublist) : as you may notice, the function calls itself. In that case, Python will first apply flattenList to sublist, then will continue to iterate.
  • If the object l is not an iterable (e.g. it’s a Point), Python will return a list composed only of l.

If you are not familiar with recursive functions, try reading this : https://www.programiz.com/python-programming/recursion

5 Likes

Thanks mellouze!

I’ve only been learning python since May, I’ve come across recursive functions but my knowledge is still pretty shaky. In fact I’m still struggling with functions in general. :confounded:

I love this forum, with every post I’m learning. :sunglasses:

1 Like

Just curious to why we would import collections? :thinking:
Can we not change the code to use isinstance(l,list) instead?

To be honest, I only copied the answer that was given here.
I guess that in this case, isintance(l,list) is sufficient, but if you would want to flatten iterables that are not list, you would have to use isinstance(l,collections.Iterable).

1 Like

because all iterables are not necessarily simple Python lists

2 Likes

@mellouze Now that makes sense. I was just thinking about the points case!
@c.poupin Thanks for the example

Another example with a recursive generator

6 Likes