迭代 RGB 颜色时如何减少代码重复?

问题描述 投票:0回答:1

我编写了一个脚本,以预设增量迭代 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 上。 还有第二个循环从 + 切换到 -(向上递增,向下递增)

我希望我已经解释清楚了 代码按原样工作,我只是想了解如何优化它。

python loops colors iteration rgb
1个回答
0
投票

你可以利用这样一个事实:只有一个 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瑜伽

如果你真的想减少代码行数,我们可以用一些 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
)。因为列表会创建整个列表。也许您只想逐个枚举这些颜色,而无需将它们保留在内存中。我在函数中添加的
list
只是为了演示。但你的问题是
iterate
,所以不需要建立一个列表。

例如

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 个值,而无需构建这些值的列表

那么,

tl;博士,

您可以使用一行迭代颜色:

p=[0,64,128,192,255]
for r,g,b in 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)))):
    print(r,g,b)
© www.soinside.com 2019 - 2024. All rights reserved.