我发现这非常接近我的问题:
Adding two items at a time in a list comprehension
但是如果我需要在单人或双人之间切换,例如:
original = list(range(10))
required = [0,0,1,2,2,3,4,4,5,6,6,7,8,8,9]
attempt1 = sum([[x,x] if x%2 == 0 else [x] for x in original],[])
attempt2 = [i for x in original for i in ([x,x] if x%2 == 0 else [x])]
sum
似乎slow,列表理解很难理解。他们都没有让我觉得简单和好。
有更好的方法吗?或者只是放弃单行方式?或者说服我,如果他们中的一个真的很好。
答案 0 :(得分:3)
就个人而言,只要我在理解中有更多非平凡的东西(例如2 for
s和1 if
),我就会使用生成器函数。
例如在你的情况下你可以使用(我认为它更具可读性,但可能是主观的):
def double_evens(inp):
for item in inp:
if item % 2 == 0:
yield item
yield item
试运行:
>>> list(double_evens(range(10)))
[0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9]
请注意,这种方法甚至可以更快(它比答案中的其他解决方案快3倍,比我在计算机上的理解速度快2倍)。采用this answer的时间框架:
from itertools import chain
def coldspeed1(mylist):
return [y for x in mylist for y in [x] * (2 - x % 2)]
def coldspeed2(mylist):
return list(chain.from_iterable([x] * (2 - x % 2) for x in mylist))
def double_evens(inp):
for item in inp:
if not item % 2:
yield item
yield item
def mseifert(inp):
return list(double_evens(inp))
def ettanany(my_list):
new_list = [[i] * 2 if i % 2 == 0 else i for i in my_list]
res = []
for i in new_list:
if isinstance(i, list):
res.extend(i)
else:
res.append(i)
return res
def no1xsyzy(original):
return [i for x in original for i in ([x,x] if x%2 == 0 else [x])]
# Timing setup
timings = {coldspeed1: [], coldspeed2: [], mseifert: [], ettanany: [], no1xsyzy: []}
sizes = [2**i for i in range(1, 20, 2)]
# Timing
for size in sizes:
mylist = list(range(size))
for func in timings:
res = %timeit -o func(mylist)
timings[func].append(res)
# Plotting
%matplotlib notebook
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(1)
ax = plt.subplot(111)
baseline = mseifert # choose one function as baseline
for func in timings:
ax.plot(sizes,
[time.best / ref.best for time, ref in zip(timings[func], timings[baseline])],
label=str(func.__name__))
#ax.set_yscale('log')
ax.set_xscale('log')
ax.set_xlabel('size')
ax.set_ylabel('time relative to {}'.format(baseline.__name__))
ax.grid(which='both')
ax.legend()
plt.tight_layout()
此图表绘制了与我的解决方案相比的相对时差。请注意,x轴(尺寸)是对数而y轴(时间差)不是。
答案 1 :(得分:1)
你走在正确的轨道上。您可以进行的简化是通过替换列表中的if..else
并将其替换为*
操作。
In [53]: [y for x in range(10) for y in [x] * (2 - x % 2)]
Out[53]: [0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9]
这大致转换为:
res = []
for x in range(10):
if not (x + 1) % 2:
res.extend([x])
else:
res.extend([x, x])
或者,您可以创建列表列表并使用itertools.chain.from_iterable
展平它:
In [54]: import itertools
In [55]: list(itertools.chain.from_iterable([x] * (2 - x % 2) for x in range(10)))
Out[55]: [0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9]
感谢评论中人们提供的有关重构其中一些解决方案的帮助。
答案 2 :(得分:0)
简单易读的解决方案如下所示:
my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
new_list = [[i] * 2 if i % 2 == 0 else i for i in my_list]
res = []
for i in new_list:
if isinstance(i, list):
res.extend(i)
else:
res.append(i)
<强>输出:强>
>>> res
[0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9]