我编写了一个脚本,以预设增量迭代 3 个 RGB 值。
您会注意到六个循环的复制/粘贴,每个循环都有所变化。
我想这六个部分可以组合成一两个父循环,以通过一个子循环而不是 6 个来递增。这有意义吗?
我的目标是减少这段代码的大小。
这是代码:
color_numbers = [0,255]
increment_between_values = [64,64,63,64]
r_val=[]
g_val=[]
b_val=[]
rgb_values=[]#FORMAT: 255,255,255
def color_function():
color_base_b = color_numbers[0]
color_top_g = color_numbers[1]
color_base_r = color_numbers[0]
for x in range(len(increment_between_values)):
r_val.append(color_numbers[0])
g_val.append(color_numbers[1])
color_base_b += increment_between_values[x]
b_val.append(color_base_b)
for x in range(len(increment_between_values)):
r_val.append(color_numbers[0])
color_top_g -= increment_between_values[x]
g_val.append(color_top_g)
b_val.append(color_base_b)
for x in range(len(increment_between_values)):
color_base_r += increment_between_values[x]
r_val.append(color_base_r)
g_val.append(color_top_g)
b_val.append(color_base_b)
for x in range(len(increment_between_values)):
r_val.append(color_base_r)
g_val.append(color_top_g)
color_base_b -= increment_between_values[x]
b_val.append(color_base_b)
for x in range(len(increment_between_values)):
r_val.append(color_base_r)
color_top_g += increment_between_values[x]
g_val.append(color_top_g)
b_val.append(color_base_b)
for x in range(len(increment_between_values)):
color_base_r -= increment_between_values[x]
r_val.append(color_base_r)
g_val.append(color_top_g)
b_val.append(color_base_b)
for t in range(len(r_val)):
print(str(r_val[t])+","+str(g_val[t])+","+str(b_val[t]))
color_function()
据我观察,每个循环的变化如下: 循环1:初始值 循环2:初始值 循环3:递增 循环4:最高值 循环5:最高值 循环 6:向下递增
这六个步骤分别针对 R、G 和 B 进行偏移 例如:当 R 在环路 1 上时,G 在环路 3 上,B 在环路 5 上。 还有第二个循环从 + 切换到 -(向上递增,向下递增)
我希望我已经解释清楚了 代码按原样工作,我只是想了解如何优化它。
你可以利用这样一个事实:只有一个 0,一个 255,还有一个东西,如果从 0 开始,则向上迭代,如果从 255 开始,则向下迭代
def mycf():
c=[0,0,0] # Starting point
l=[0,64,128,192,255] # Possible values
res=[] # Result
for p0 in range(3): # Where is 0 in c
c[p0]=0
for p255 in range(3): # Where in 255 in c
if p255==p0: continue # Cannot be where is 0
c[p255]=255
pother=3-p0-p255 # Where is the other value (sum p0+p255+pother = 0+1+2 (in another order) = 3. So 3-p0-p255 is the pother)
if c[pother]!=l[0]: l=l[::-1] # Iterates possible value from where we are. That is either 0 or 255. So if we are not at l[0], reverse it
# The if is for clarity. In fact we could have started with l=[255,192,128,64,0] and reverted each times inconditionnaly
for x in l[1:]:
c[pother]=x
res.append(list(c))
return res
如果你真的想减少代码行数,我们可以用一些 itertools Yoga 来做一行代码(但是一大行)
import itertools
def listRgb(*p):
return list(itertools.chain(*itertools.chain(*zip(itertools.islice(zip(*(itertools.permutations([0,255,x]) for x in p[1:])),0,None,2),itertools.islice(zip(*(itertools.permutations([0,255,x]) for x in p[-2::-1])),1,None,2)))))
listRgb(0,64,128,192,255)
说明:
itertools.permutations([0,255,x])
都是 0,255 和 x 的组合,按确定顺序 (0,255,x), (0,x,255), (255,0,x), ... 或者更准确地说,它是一个迭代器浏览那些三胞胎(其中 6 个)
所以
(itertools.permutations([0,255,x]) for x in p[1:])
是一个遍历所有这些迭代器的迭代器,其中 x 是 4 个值 64,128,192,255 中的任何一个。因此,如果我们展开这个“迭代器的迭代器”,我们将得到 6 个三元组序列中的 4 个序列。
因此
zip(*(itertools.permutations([0,255,x]) for x in p[1:]))
返回由每个序列的一个元素组成的四元组。所以是三元组的四元组的迭代器。其中 6 个。对应于 0、255 和 x 的每个可能的排列,以及三元组的每个 x 值。 x 按升序排列。我们就快到了。只是,我们有一半的时间希望它们按降序排列。
zip(*(itertools.permutations([0,255,x]) for x in p[-2::-1]))
是按降序排列的同一件事
请注意,第一个跳过 0(这与上一次迭代的最后一个迭代是多余的),而第二个跳过 255(同样)。
因此,我们对第一个序列(升序序列)中的一半感兴趣,对第二个序列中的一半感兴趣。
我们可以用
islice
将 2 个切片之一
itertools.islice(zip(*(itertools.permutations([0,255,x]) for x in p[1:])),0,None,2)
保持升序itertools.islice(zip(*(itertools.permutations([0,255,x]) for x in p[-2::-1])),1,None,2)
下降的
我们可以使用 zip 从这些半部分中选择一个(这是一种从我们选择序列的位置交替的方式)
zip(itertools.islice(zip(*(itertools.permutations([0,255,x]) for x in p[1:])),0,None,2),itertools.islice(zip(*(itertools.permutations([0,255,x]) for x in p[-2::-1])),1,None,2))
快到了。 因为我们这里有的是(从最后一个拉链)成对的 4 个三胞胎;其中 3 个,这是由 4 个三元组组成的三元组(或者,准确地说,如果我们迭代它,迭代器就会计算出它。目前,我们还没有进行任何计算。它只是一个迭代器),我们需要连接结果。由于 itertools 的全部目的是将事物保留为迭代器(在我们真正迭代事物之前不使用任何内存或 cpu),而不是将其转换为列表并连接它们,所以我使用
chain
它将迭代每个3 对一组接一组,得到 6 个连体,
所以
itertools.chain(*zip(itertools.islice(zip(*(itertools.permutations([0,255,x]) for x in p[1:])),0,None,2),itertools.islice(zip(*(itertools.permutations([0,255,x]) for x in p[-2::-1])),1,None,2)))
是一个迭代器,迭代 6 个三元组的 4 连组。同样,我们只想迭代三元组。所以,再次chain
itertools.chain(*itertools.chain(*zip(itertools.islice(zip(*(itertools.permutations([0,255,x]) for x in p[1:])),0,None,2),itertools.islice(zip(*(itertools.permutations([0,255,x]) for x in p[-2::-1])),1,None,2))))
是最终的迭代器。值为三元组的那个
事实上,它应该是我的函数返回的内容(而不是返回其中的
list
)。因为列表会创建整个列表。也许您只是想逐个枚举这些颜色,而不需要将它们保留在内存中。
例如
import itertools
def itRgb(*p):
return itertools.chain(*itertools.chain(*zip(itertools.islice(zip(*(itertools.permutations([0,255,x]) for x in p[1:])),0,None,2),itertools.islice(zip(*(itertools.permutations([0,255,x]) for x in p[-2::-1])),1,None,2))))
for r,g,b in itRgb(*range(256)):
print(r,g,b)
使用步骤 1 打印 1530 个值,而无需构建这些值的列表