我正在寻找一个内存/ CPU高效的单行程序来对列表中每m个元素中的n进行二次采样。到目前为止我有:
sb = [11,12,21,22,31,32]*4 #stream buffer, e.g. 4 identical frames
ci = 1 #1-indexed channel index
cs = 2 #channel (sample) size
nc = 3 #number of channels in each frame
fs = nc*cs #frame size
[i for l in [sb[j+ci-1:j+ci-1+cs] for j
in [x*fs+ci-1 for x in xrange(len(sb)/fs)]] for i in l]
Out: [11, 12, 11, 12, 11, 12, 11, 12]
分解我正在创建一个样本列表列表,然后将其展平为包含[i for l in ll for i in l]
的一维列表
或者,不是一个班轮,但更容易阅读,我可以做:
os = []
for i in [sb[j+ci-1:j+ci-1+cs] for j in [x*fs+ci-1 for x in xrange(len(sb)/fs)]]: os = os+i
例如,与cs=1
特定情况的简单简写:sb[ci-1::fs]
进行比较时,两种解决方案看起来都太复杂了。
你能帮我提出一个不错的解决方案吗?
答案 0 :(得分:2)
以下内容对我来说似乎相当可读(而且效率也相当高):
from itertools import chain
sb = [11, 12, 21, 22, 31, 32]*4 # stream buffer, e.g. 4 identical frames
ci = 1 # 1-indexed channel index
cs = 2 # channel size
nc = 3 # number of channels in each frame
fs = nc*cs # frame size
result = list(chain.from_iterable(sb[i: i+cs] for i in xrange(ci-1, len(sb), fs)))
print(result) # -> [11, 12, 11, 12, 11, 12, 11, 12]
答案 1 :(得分:1)
我将大部分索引移动到range()
计算中。然后将索引显示为子列表的速度更快 - 请参阅下面的时间:
sb = [11,12,21,22,31,32]*4 #stream buffer, e.g. 4 identical frames
ci = 1 #1-indexed channel index
cs = 2 #channel size
nc = 3 #number of channels in each frame
fs = nc*cs #frame size
for ci in range(1,4):
print [x for y in [sb[x:x+cs] for x in range((ci-1)*cs,len(sb),fs)] for x in y]
输出:
[11, 12, 11, 12, 11, 12, 11, 12]
[21, 22, 21, 22, 21, 22, 21, 22]
[31, 32, 31, 32, 31, 32, 31, 32]
我将大部分工作转移到range()
调用生成的子列表列表中,其余的是将子列表简单地分解为一个列表。
range((ci-1)*cs,len(sb), fs)
| | |________ frame size, range will use steps the size of the frame
| |______________ till end of data
|________________________ starting at (ci-1) * channel size
for ci = 1 it starts at 0, 6,12,18,....
for ci = 2 it starts at 2, 8,14,....
for ci = 3 it starts at 4, 10,...
for ci = 4 it starts at 6, ...
and increases by fs = 6 until end of data. The list comp then gets a sublist of len cs
and the rest of the list-comp flattens it down from list of list to a simpler list
定时:
import timeit
print timeit.timeit(stmt='''
sb = [11,12,21,22,31,32]*4*5 #stream buffer, e.g. 4 identical frames
ci = 1 #1-indexed channel index
cs = 2 #channel size
nc = 3 #number of channels in each frame
fs = nc*cs #frame size
for ci in range(1,4):
[x for y in [sb[x:x+cs] for x in range((ci-1)*cs,len(sb),fs)] for x in y]
''', setup='pass', number=10000) # 0.588474035263
print timeit.timeit(stmt='''
sb = [11,12,21,22,31,32]*4*5 #stream buffer, e.g. 4 identical frames
ci = 1 #1-indexed channel index
cs = 2 #channel size
nc = 3 #number of channels in each frame
fs = nc*cs #frame size
for ci in range(1,4):
[i for l in [sb[j+ci-1:j+ci-1+cs] for j in [x*fs+ci-1 for x in xrange(len(sb)/fs)]] for i in l]
''', setup='pass', number=10000) # 0.734045982361
答案 2 :(得分:-1)
<强>代码强>:
sb = [11,12,21,22,31,32] * 4
ci = 0
cs = 2
nc = 3
fs = cs * nc
result = list(sum(zip(*[sb[i::fs] for i in range(ci, ci+cs)]),()))
<强>输出强>:
[11, 12, 11, 12, 11, 12, 11, 12]
我建议将ci
设置为基于0的索引以匹配python的语法,但如果您坚持,更新func很简单,只需将所有ci
替换为ci-1
即可。 ci
。
它与您原来的方法基本相同,只是更清洁一点,它可以扩展到不同的cs
,nc
和get_directory_property(MY_LIBRARIES_NAMES BUILDSYSTEM_TARGETS)
。
答案 3 :(得分:-1)
我建议使用更清晰的变量名称而不是注释,不要使用单行。
<强>鉴于强>
import itertools as it
stream = [11, 12, 21, 22, 31, 32] * 4
ch_idx = 1
ch_size = 2
num_chs = 3
<强>代码强>
使用grouper
itertools recipe:
channels = grouper(ch_size, stream)
frames = grouper(num_chs, channels)
list(it.chain.from_iterable(*it.islice(zip(*frames), ch_idx)))
# [11, 12, 11, 12, 11, 12, 11, 12]
作为单行,它看起来如下:
list(it.chain.from_iterable(*it.islice(zip(*grouper(num_chs, grouper(ch_size, stream))), ch_idx)))
# [11, 12, 11, 12, 11, 12, 11, 12]
<强>详情
grouper
配方实现如下:
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return zip_longest(*args, fillvalue=fillvalue)
另请参阅more_itertools
第三方库以了解预先实施的食谱。