Created
October 24, 2014 00:31
-
-
Save zvodd/a15ce9479bb505584ccb to your computer and use it in GitHub Desktop.
Flatten lists of lists. Including callback argument to filter iterable types.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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