【发布时间】:2017-08-05 13:00:25
【问题描述】:
如果我有一个列表,例如。
[1,2,3]
还有一个函数 f(),我如何插入这样的新列表:
[1, f(1), 2, f(2), 3, f(3)]?
【问题讨论】:
-
您是否在这里尝试过任何解决方案?很高兴看到您尝试帮助纠正您的问题。
如果我有一个列表,例如。
[1,2,3]
还有一个函数 f(),我如何插入这样的新列表:
[1, f(1), 2, f(2), 3, f(3)]?
【问题讨论】:
你可以使用:
[y for x in data for y in (x,f(x))]
data 是初始列表,f 当然是你要应用的功能。
例如,如果f 是str 函数(将数字转换为其文本等价物),它将生成:
>>> data = [1,2,3]
>>> f = str
>>> [y for x in data for y in (x,f(x))]
[1, '1', 2, '2', 3, '3']
所以这里我们得到[1, '1', 2, '2', 3, '3'],其中1是初始1,'1'是f(1)。
基准测试:我将following test setup 更改为:
import pandas as pd
from timeit import timeit
from itertools import chain
wvo = lambda d, f: [y for x in d for y in (x,f(x))]
max = lambda d, f: list(chain.from_iterable(zip(d, map(f, d))))
mrc = lambda d, f: sum([[x,f(x)] for x in d], [])
chi = lambda d,f: [j for k in map(lambda x: (x, f(x)), d) for j in k]
mar = lambda d,f: [ee for e in zip (d, map (f, d)) for ee in e]
results = pd.DataFrame(
index=pd.Index([1, 3, 10, 30, 100, 300,
1000, 3000, 10000, 30000, 100000], name='N'),
columns='wvo max mrc chi mar'.split(),
dtype=float
)
for i in results.index:
pd.concat([df] * i, ignore_index=True)
d = list(range(i))
f = str
for j in results.columns:
stmt = '{}(d,f)'.format(j)
setp = 'from __main__ import d, f, {}'.format(j)
results.set_value(i, j, timeit(stmt, setp, number=10))
这意味着我们可以使用 pandas 测试不同文件大小的不同答案。对于每个配置,我们使用 timeit 执行 10 次测试。
这会生成以下时间(以秒为单位):
wvo max mrc chi mar
N
1 0.000016 0.000029 0.000018 0.000022 0.000020
3 0.000026 0.000029 0.000031 0.000034 0.000026
10 0.000057 0.000053 0.000061 0.000076 0.000062
30 0.000145 0.000122 0.000210 0.000200 0.000145
100 0.000440 0.000347 0.000899 0.000588 0.000407
300 0.001263 0.000637 0.004416 0.001721 0.000680
1000 0.002425 0.001897 0.040877 0.003796 0.002325
3000 0.009269 0.009798 0.289162 0.015486 0.008430
10000 0.037131 0.032563 3.823171 0.044008 0.030609
30000 0.078577 0.060828 53.803486 0.096703 0.066899
100000 0.255477 0.195669 1094.482380 0.289030 0.191143
或者相对而言(最好是1.00):
wvo max mrc chi mar Best
N
1 1.00 1.78 1.11 1.36 1.19 wvo
3 1.03 1.15 1.23 1.32 1.00 mar
10 1.08 1.00 1.17 1.45 1.18 max
30 1.19 1.00 1.73 1.65 1.20 max
100 1.27 1.00 2.59 1.69 1.17 max
300 1.98 1.00 6.93 2.70 1.07 max
1000 1.28 1.00 21.55 2.00 1.23 max
3000 1.10 1.16 34.30 1.84 1.00 mar
10000 1.21 1.06 124.90 1.44 1.00 mar
30000 1.29 1.00 884.52 1.59 1.10 max
100000 1.34 1.02 5725.98 1.51 1.00 mar
【讨论】:
In [18]: lst = [1,2,3]
In [19]: def f(x):
...: return x**2
...:
In [20]: from itertools import chain
In [21]: list(chain.from_iterable(zip(lst, map(f, lst))))
Out[21]: [1, 1, 2, 4, 3, 9]
【讨论】:
与威廉的回答略有不同的方法,避免了两个循环:
sum([[x,f(x)] for x in my_list], [])
[x, f(x)] 创建一个包含两个元素的列表,其中包含当前元素和应用于它的函数。
sum(..., []) 将列表展平。
【讨论】:
sum不用循环就可以工作,而且重复的列表串联效率更高……这样就差很多了;有一个循环并不是一件坏事。
__add__ 或 __iadd__ 因为在前一种情况下,这将导致 O(n^2)算法。
[]没有更新。所以这可能意味着它使用__add__。这个question 证实了这一点。
sum 应该不用于可迭代对象。这是非常低效的。甚至the documentation 也明确指出应该改用itertools.chain。
O(n^2) 的复杂性,并且有两个循环完全不是一件坏事,但我不同意这样的效率低得多。对这两种方法进行测试导致每种情况下的时间相当。尽管它不是最可行的解决方案,但内部方法的效率远低于顶级循环的说法是不正确的。此外,考虑到他们提供的测试,我真的怀疑 OP 是否需要一种非常高效的方法。
>>> data = [1, 2, 3]
>>> f = lambda x : x + 1
>>> [ee for e in zip (data, map (f, data)) for ee in e]
[1, 2, 2, 3, 3, 4]
【讨论】:
您可以使用map 和list comprehension:
f = lambda x: x**3
a = [1, 2, 3]
output = [j for k in map(lambda x: (x, f(x)), a) for j in k]
print(output)
输出:
[1, 1, 2, 8, 3, 27]
【讨论】: