@S.Lott: Вы вдохновили меня писать timeit приложение.
я полагал, что это будет также варьироваться на основе количества разделов (количество итераторов в рамках контейнерного списка) - Ваш комментарий не упоминал, сколько разделов там имело эти тридцать объектов. Этот график сглаживает тысячу объектов в каждом выполнении с переменным количеством разделов. Объекты равномерно распределяются среди разделов.
Код (Python 2.6):
#!/usr/bin/env python2.6
"""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_)
METHODS = ['itertools', 'itertools_iterable', 'reduce', 'reduce_lambda',
'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 test import %s_flatten as flatten' % 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.show()
Редактирование: Решительный для создания этого общественной Wiki.
Примечание: METHODS
должен, вероятно, быть накоплен с декоратором, но я полагаю, что для людей было бы легче считать этот путь.
В PowerShell V2 со сплаттингом все тривиально. bar просто превращается в:
function bar { foo @args }
Splatting будет рассматривать элементы массива как отдельные аргументы, а не передавать их как один аргумент массива.
В PowerShell V1 это сложно, есть способ сделать это для позиционного аргументы. Дана функция foo:
function foo { write-host args0 $args[0] args1 $args[1] args2 $args[2] }
Теперь вызовите ее из bar с помощью метода Invoke ()
в блоке сценария функции foo
function bar { $OFS=','; "bar args: $args"; $function:foo.Invoke($args) }
, который при использовании выглядит как
PS (STA) (16) > bar 1 2 3 bar args: 1,2,3 args0 1 args1 2 args2 3
.
# use the pipe, Luke!
file1.ps1
---------
$args | write-host
$args | .\file2.ps1
file2.ps1
---------
process { write-host $_ }