Skip to content

Instantly share code, notes, and snippets.

@zvodd
Created October 24, 2014 00:31
Show Gist options
  • Save zvodd/a15ce9479bb505584ccb to your computer and use it in GitHub Desktop.
Save zvodd/a15ce9479bb505584ccb to your computer and use it in GitHub Desktop.
Flatten lists of lists. Including callback argument to filter iterable types.
import collections
# ignore functions
ignore_strings = lambda x: isinstance(x, basestring)
ignore_dicts = lambda x: isinstance(x, dict)
def list_flatten(*ilist, **kwargs):
"""
Flattens nested indexable iterables, i.e lists of lists
By default treats strings and dicts as scalar values
LIST ORDER IS ALWAYS IN REVERSE. Use reversed() to reorder, if needed.
Kwarg "ignore" is list of functions
Each function takes a single argument that returns True if a value should be treated as a scalar
or false if it should be iterated: must be indexable with integer e.g. iterable[0]
Dicts are always treated as scalars.
String can be treated as iterables if ignore=[]
"""
# ignore_checks is a list of functions
# returning True to indicate an iterable should be treated as single element
ignore_checks = []
if 'ignore' in kwargs and isinstance(kwargs['ignore'], list):
ignore_checks = kwargs['ignore']
#always ignore dicts
if ignore_dicts not in ignore_checks:
ignore_checks.append(ignore_dicts)
else:
#defaults to ignoring strings and dicts
ignore_checks += [ignore_strings, ignore_dicts]
# this would be to hard to read with indexed tuples, but they should be used instead
itree = [{'item':ilist, 'index':len(ilist)-1}]
newlist = []
pdict = itree[0]
while itree:
if pdict['index'] >= 0 :
citem = pdict['item'][pdict['index']]
if isinstance(citem, collections.Iterable) \
and not True in [func(citem) for func in ignore_checks]:
itree.append({'item': citem ,'index':len(citem)-1})
pdict['index'] -= 1
pdict = itree[-1]
# continue
else:
newlist.append(citem)
pdict['index'] -= 1
# continue
else:
itree.pop()
if len(itree) > 0:
pdict = itree[-1]
# continue
else:
#we are done
break
return newlist
if __name__ == "__main__":
# simple tests
tl1 = [1, 2]
tl2 = ['a','b','c']
tl3 = tl1 + [3, 4, [5, 6, 'seven']] + [8]
tl4 = tl1 + (tl2)
tl5 = ["WHAT","IS","THIS"]
print list_flatten(1, [2, [3]], 4)
print list_flatten(tl3)
print list_flatten([tl1+tl2+[tl1+[tl2]]])
print list_flatten([[7,6], 5, 4, [3]], tl5, 2, 1)
print list_flatten([1,2], "String", ['a','b','c'],['1a','2a','3a'])
print list_flatten([1,2], "String", dict([('a',1),('b',2)]), ['a','b','c'],['1a','2a','3a'])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment