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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | #!/usr/bin/env python2.6 #http://stackoverflow.com/questions/406121/flattening-a-shallow-list-in-python/408281#408281 """Usage: %prog item_count""" from __future__ import print_function import collections import itertools import operator from timeit import Timer import sys import matplotlib.pyplot as pyplot def itertools_flatten(iter_lst): return list(itertools.chain(*iter_lst)) def itertools_iterable_flatten(iter_iter): return list(itertools.chain.from_iterable(iter_iter)) def reduce_flatten(iter_lst): return reduce(operator.add, map(list, iter_lst)) def reduce_lambda_flatten(iter_lst): return reduce(operator.add, map(lambda x: list(x), [i for i in iter_lst])) def comprehension_flatten(iter_lst): return list(item for iter_ in iter_lst for item in iter_) def iadd_flatten(aList): return reduce(operator.iadd, aList, []) def list_iadd_flatten(aList): return reduce(list.__iadd__, aList, []) def list_comprehension_flatten( aList ): return [y for x in aList for y in x] METHODS = ['itertools', 'itertools_iterable', 'comprehension', 'iadd', 'list_iadd', 'list_comprehension'] def _time_test_assert(iter_lst): """Make sure all methods produce an equivalent value. :raise AssertionError: On any non-equivalent value.""" callables = (globals()[method + '_flatten'] for method in METHODS) results = [callable(iter_lst) for callable in callables] if not all(result == results[0] for result in results[1:]): raise AssertionError def time_test(partition_count, item_count_per_partition, test_count=10000): """Run flatten methods on a list of :param:`partition_count` iterables. Normalize results over :param:`test_count` runs. :return: Mapping from method to (normalized) microseconds per pass. """ iter_lst = [[dict()] * item_count_per_partition] * partition_count print('Partition count: ', partition_count) print('Items per partition:', item_count_per_partition) _time_test_assert(iter_lst) test_str = 'flatten(%r)' % iter_lst result_by_method = {} for method in METHODS: setup_str = 'from %s import %s_flatten as flatten' % (__name__, method) t = Timer(test_str, setup_str) per_pass = test_count * t.timeit(number=test_count) / test_count print('%20s: %.2f usec/pass' % (method, per_pass)) result_by_method[method] = per_pass return result_by_method if __name__ == '__main__': if len(sys.argv) != 2: raise ValueError('Need a number of items to flatten') item_count = int(sys.argv[1]) partition_counts = [] pass_times_by_method = collections.defaultdict(list) for partition_count in xrange(1, item_count): if item_count % partition_count != 0: continue items_per_partition = item_count / partition_count result_by_method = time_test(partition_count, items_per_partition) partition_counts.append(partition_count) for method, result in result_by_method.iteritems(): pass_times_by_method[method].append(result) for method, pass_times in pass_times_by_method.iteritems(): pyplot.plot(partition_counts, pass_times, label=method) pyplot.legend() pyplot.title('Flattening Comparison for %d Items' % item_count) pyplot.xlabel('Number of Partitions') pyplot.ylabel('Microseconds') pyplot.savefig('p%d.png' % item_count) pyplot.show() |
IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMi42CiNodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzQwNjEyMS9mbGF0dGVuaW5nLWEtc2hhbGxvdy1saXN0LWluLXB5dGhvbi80MDgyODEjNDA4MjgxCiIiIlVzYWdlOiAlcHJvZyBpdGVtX2NvdW50IiIiCgpmcm9tIF9fZnV0dXJlX18gaW1wb3J0IHByaW50X2Z1bmN0aW9uCgppbXBvcnQgY29sbGVjdGlvbnMKaW1wb3J0IGl0ZXJ0b29scwppbXBvcnQgb3BlcmF0b3IKZnJvbSB0aW1laXQgaW1wb3J0IFRpbWVyCmltcG9ydCBzeXMKCmltcG9ydCBtYXRwbG90bGliLnB5cGxvdCBhcyBweXBsb3QKCmRlZiBpdGVydG9vbHNfZmxhdHRlbihpdGVyX2xzdCk6CiAgICByZXR1cm4gbGlzdChpdGVydG9vbHMuY2hhaW4oKml0ZXJfbHN0KSkKCmRlZiBpdGVydG9vbHNfaXRlcmFibGVfZmxhdHRlbihpdGVyX2l0ZXIpOgogICAgcmV0dXJuIGxpc3QoaXRlcnRvb2xzLmNoYWluLmZyb21faXRlcmFibGUoaXRlcl9pdGVyKSkKCmRlZiByZWR1Y2VfZmxhdHRlbihpdGVyX2xzdCk6CiAgICByZXR1cm4gcmVkdWNlKG9wZXJhdG9yLmFkZCwgbWFwKGxpc3QsIGl0ZXJfbHN0KSkKCmRlZiByZWR1Y2VfbGFtYmRhX2ZsYXR0ZW4oaXRlcl9sc3QpOgogICAgcmV0dXJuIHJlZHVjZShvcGVyYXRvci5hZGQsIG1hcChsYW1iZGEgeDogbGlzdCh4KSwgW2kgZm9yIGkgaW4gaXRlcl9sc3RdKSkKCmRlZiBjb21wcmVoZW5zaW9uX2ZsYXR0ZW4oaXRlcl9sc3QpOgogICAgcmV0dXJuIGxpc3QoaXRlbSBmb3IgaXRlcl8gaW4gaXRlcl9sc3QgZm9yIGl0ZW0gaW4gaXRlcl8pCgpkZWYgaWFkZF9mbGF0dGVuKGFMaXN0KToKICAgIHJldHVybiByZWR1Y2Uob3BlcmF0b3IuaWFkZCwgYUxpc3QsIFtdKQoKZGVmIGxpc3RfaWFkZF9mbGF0dGVuKGFMaXN0KToKICAgIHJldHVybiByZWR1Y2UobGlzdC5fX2lhZGRfXywgYUxpc3QsIFtdKQoKZGVmIGxpc3RfY29tcHJlaGVuc2lvbl9mbGF0dGVuKCBhTGlzdCApOgogICAgcmV0dXJuIFt5IGZvciB4IGluIGFMaXN0IGZvciB5IGluIHhdCgpNRVRIT0RTID0gWydpdGVydG9vbHMnLCAnaXRlcnRvb2xzX2l0ZXJhYmxlJywgCiAgICAgICAgICAgJ2NvbXByZWhlbnNpb24nLCAnaWFkZCcsICdsaXN0X2lhZGQnLCAnbGlzdF9jb21wcmVoZW5zaW9uJ10KCmRlZiBfdGltZV90ZXN0X2Fzc2VydChpdGVyX2xzdCk6CiAgICAiIiJNYWtlIHN1cmUgYWxsIG1ldGhvZHMgcHJvZHVjZSBhbiBlcXVpdmFsZW50IHZhbHVlLgogICAgOnJhaXNlIEFzc2VydGlvbkVycm9yOiBPbiBhbnkgbm9uLWVxdWl2YWxlbnQgdmFsdWUuIiIiCiAgICBjYWxsYWJsZXMgPSAoZ2xvYmFscygpW21ldGhvZCArICdfZmxhdHRlbiddIGZvciBtZXRob2QgaW4gTUVUSE9EUykKICAgIHJlc3VsdHMgPSBbY2FsbGFibGUoaXRlcl9sc3QpIGZvciBjYWxsYWJsZSBpbiBjYWxsYWJsZXNdCiAgICBpZiBub3QgYWxsKHJlc3VsdCA9PSByZXN1bHRzWzBdIGZvciByZXN1bHQgaW4gcmVzdWx0c1sxOl0pOgogICAgICAgIHJhaXNlIEFzc2VydGlvbkVycm9yCgpkZWYgdGltZV90ZXN0KHBhcnRpdGlvbl9jb3VudCwgaXRlbV9jb3VudF9wZXJfcGFydGl0aW9uLCB0ZXN0X2NvdW50PTEwMDAwKToKICAgICIiIlJ1biBmbGF0dGVuIG1ldGhvZHMgb24gYSBsaXN0IG9mIDpwYXJhbTpgcGFydGl0aW9uX2NvdW50YCBpdGVyYWJsZXMuCiAgICBOb3JtYWxpemUgcmVzdWx0cyBvdmVyIDpwYXJhbTpgdGVzdF9jb3VudGAgcnVucy4KICAgIDpyZXR1cm46IE1hcHBpbmcgZnJvbSBtZXRob2QgdG8gKG5vcm1hbGl6ZWQpIG1pY3Jvc2Vjb25kcyBwZXIgcGFzcy4KICAgICIiIgogICAgaXRlcl9sc3QgPSBbW2RpY3QoKV0gKiBpdGVtX2NvdW50X3Blcl9wYXJ0aXRpb25dICogcGFydGl0aW9uX2NvdW50CiAgICBwcmludCgnUGFydGl0aW9uIGNvdW50OiAgICAnLCBwYXJ0aXRpb25fY291bnQpCiAgICBwcmludCgnSXRlbXMgcGVyIHBhcnRpdGlvbjonLCBpdGVtX2NvdW50X3Blcl9wYXJ0aXRpb24pCiAgICBfdGltZV90ZXN0X2Fzc2VydChpdGVyX2xzdCkKICAgIHRlc3Rfc3RyID0gJ2ZsYXR0ZW4oJXIpJyAlIGl0ZXJfbHN0CiAgICByZXN1bHRfYnlfbWV0aG9kID0ge30KICAgIGZvciBtZXRob2QgaW4gTUVUSE9EUzoKICAgICAgICBzZXR1cF9zdHIgPSAnZnJvbSAlcyBpbXBvcnQgJXNfZmxhdHRlbiBhcyBmbGF0dGVuJyAlIChfX25hbWVfXywgbWV0aG9kKQogICAgICAgIHQgPSBUaW1lcih0ZXN0X3N0ciwgc2V0dXBfc3RyKQogICAgICAgIHBlcl9wYXNzID0gdGVzdF9jb3VudCAqIHQudGltZWl0KG51bWJlcj10ZXN0X2NvdW50KSAvIHRlc3RfY291bnQKICAgICAgICBwcmludCgnJTIwczogJS4yZiB1c2VjL3Bhc3MnICUgKG1ldGhvZCwgcGVyX3Bhc3MpKQogICAgICAgIHJlc3VsdF9ieV9tZXRob2RbbWV0aG9kXSA9IHBlcl9wYXNzCiAgICByZXR1cm4gcmVzdWx0X2J5X21ldGhvZAoKaWYgX19uYW1lX18gPT0gJ19fbWFpbl9fJzoKICAgIGlmIGxlbihzeXMuYXJndikgIT0gMjoKICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdOZWVkIGEgbnVtYmVyIG9mIGl0ZW1zIHRvIGZsYXR0ZW4nKQogICAgaXRlbV9jb3VudCA9IGludChzeXMuYXJndlsxXSkKICAgIHBhcnRpdGlvbl9jb3VudHMgPSBbXQogICAgcGFzc190aW1lc19ieV9tZXRob2QgPSBjb2xsZWN0aW9ucy5kZWZhdWx0ZGljdChsaXN0KQogICAgZm9yIHBhcnRpdGlvbl9jb3VudCBpbiB4cmFuZ2UoMSwgaXRlbV9jb3VudCk6CiAgICAgICAgaWYgaXRlbV9jb3VudCAlIHBhcnRpdGlvbl9jb3VudCAhPSAwOgogICAgICAgICAgICBjb250aW51ZQogICAgICAgIGl0ZW1zX3Blcl9wYXJ0aXRpb24gPSBpdGVtX2NvdW50IC8gcGFydGl0aW9uX2NvdW50CiAgICAgICAgcmVzdWx0X2J5X21ldGhvZCA9IHRpbWVfdGVzdChwYXJ0aXRpb25fY291bnQsIGl0ZW1zX3Blcl9wYXJ0aXRpb24pCiAgICAgICAgcGFydGl0aW9uX2NvdW50cy5hcHBlbmQocGFydGl0aW9uX2NvdW50KQogICAgICAgIGZvciBtZXRob2QsIHJlc3VsdCBpbiByZXN1bHRfYnlfbWV0aG9kLml0ZXJpdGVtcygpOgogICAgICAgICAgICBwYXNzX3RpbWVzX2J5X21ldGhvZFttZXRob2RdLmFwcGVuZChyZXN1bHQpCiAgICBmb3IgbWV0aG9kLCBwYXNzX3RpbWVzIGluIHBhc3NfdGltZXNfYnlfbWV0aG9kLml0ZXJpdGVtcygpOgogICAgICAgIHB5cGxvdC5wbG90KHBhcnRpdGlvbl9jb3VudHMsIHBhc3NfdGltZXMsIGxhYmVsPW1ldGhvZCkKICAgIHB5cGxvdC5sZWdlbmQoKQogICAgcHlwbG90LnRpdGxlKCdGbGF0dGVuaW5nIENvbXBhcmlzb24gZm9yICVkIEl0ZW1zJyAlIGl0ZW1fY291bnQpCiAgICBweXBsb3QueGxhYmVsKCdOdW1iZXIgb2YgUGFydGl0aW9ucycpCiAgICBweXBsb3QueWxhYmVsKCdNaWNyb3NlY29uZHMnKQogICAgcHlwbG90LnNhdmVmaWcoJ3AlZC5wbmcnICUgaXRlbV9jb3VudCkKICAgIHB5cGxvdC5zaG93KCkKCg==


