Flatten a list
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | def flattenlist(L):
import types
WhiteTypes = ('StringType', 'UnicodeType', 'StringTypes', 'ListType',
'ObjectType', 'TupleType')
BlackTypes= tuple( [getattr(types, x) for x in dir(types)
if not x.startswith('_')
and x not in whites] )
tmp = []
def core(L):
if not hasattr(L,'__iter__'):
return [L]
else :
for i in L:
if isinstance(i,BlackTypes):
tmp.append(i)
continue
if type(i) == type(str()):
tmp.append(i)
else:
core(i)
return tmp
return core(L)
#Examples x=[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[['x']]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
>>> flattenlist(x)
['x']
>>> x=(((((1)))))
>>> flattenlist(x)
[1]
>>> x=[(),(),[]]
>>> flattenlist(x)
[]
>>> x=[(1),('1'),[1.0]]
>>> flattenlist(x)
[1, '1', 1.0]
>>> x=[[[[[[(((([1,1]))))]]]]]]
>>> flattenlist(x)
[1, 1]
>>> x=1
>>> flattenlist(x)
[1]
>>> x=flattenlist
>>> flattenlist(x)
[<function flattenlist at 0x16a8320>]
>>>
|
inspired by http://code.activestate.com/recipes/363051-flatten/
it's a combination of recursion and closures it always return a list either cropped down to one level or if the input is small just a list wrapped around it
Note : in line 17 it just checks if it is instance of any of the types we need
i hope you like it :-)
I don't like how it makes certain assumptions about the structure of the
types
module and uses the module to generate a blacklist by subtracting a predefined whitelist. But more importantly,eval
is evil and should be avoided,getattr
is better suited in this case.You could probably sanitize that bit a bit like so:
Or if you want to avoid one-liners:
This will still break if the module ever contains anything that is not a
type
(StringTypes
is atuple
, btw) and is not prefixed, though. To fix this you could add the restrictiontype(x) == type
(ortype(x) != type
in the verbose version).Other than that it is very concise and pretty solid.
That function is quite big to do something so simple!
I made this other function some time ago, which as I just tested my self, does everything yours does.
Hope you don't mind! -Sunjay03
Alan Plum Thanks for your Comment while the rest of the code is doing was it supposed to do , yes it's true my assumptions about the types module makes the code bad...
I totally agree that it needs to add some simpler white and blacklist "handling" ... as you proposed . i was just concentrated only on the core function and i totally forget to clean it up so not to put this very bad bad line --> Types =dir(types)[:-5] )-:
I totally regret i will not do it again ;) :-) :P Anyway thanks for your words
Sunjay Varma My intention was to make my version of flattenlist using closures because from what i saw there where already being made other solutions (recursive,recursive-iterator,for loop etc...)from other people .
My version just came up like this because i wasn't concern about less lines of code and i am pretty sure i can make a smaller version if that is my intention
cheers
Alan Plum
I updated the code
It's much easier to just assume that everything with an __iter__ is a valid iterator and once you talk about iterator rather than lists you can minify the flatten function to this:
Should a list flattener flatten strings? Or tuples? ...
Answer to Paddy:
The API is wrong. It is upto to the caller to determine which types are atomic. In some circumstances, strings and tuples should be recursed into, and in other circumstances it might not be useful at all.
I come from a lisp background and this is what I came up with:
test:
returns: