减少Python中的二进制模式

减少Python中的二进制模式,python,Python,我有一个我认为有点有趣的问题,即使只是从编程练习的角度来看 我有一长串的二进制模式,我想把它们简化成一个更紧凑的形式,呈现给用户。要遵循的符号是“-”可以表示“1”或“0”,因此['1011','1010']可以表示为['101-']和 ['1100', '1000', '0100', '0000', '1111', '1011', '0111', '0011'] 可以用['-00','-11']表示。注意所有的模式都是相同的长度(尽管很可能超过4位) 扩展模式相当简单,减少模式则有点棘手 我

我有一个我认为有点有趣的问题,即使只是从编程练习的角度来看

我有一长串的二进制模式,我想把它们简化成一个更紧凑的形式,呈现给用户。要遵循的符号是“-”可以表示“1”或“0”,因此
['1011','1010']
可以表示为
['101-']

['1100', '1000', '0100', '0000', '1111', '1011', '0111', '0011']
可以用
['-00','-11']
表示。注意所有的模式都是相同的长度(尽管很可能超过4位)

扩展模式相当简单,减少模式则有点棘手

我已经想出了一些代码来实现这一点,但它很长,很慢,而且有点难以阅读

def reducePatterns(patterns):
    '''Reduce patterns into compact dash notation'''
    newPatterns = []  #reduced patterns
    matched = []      #indexes with a string that was already matched
    for x,p1 in enumerate(patterns):    #pattern1
        if x in matched: continue       #skip if this pattern has already been matched
        for y,p2 in enumerate(patterns[x+1:],1):
            if x+y in matched: continue #skip if this pattern has already been matched
            diffs=0     # number of differences found
            for idx,bit in enumerate(zip(p1,p2)):
                if bit[0] != bit [1]:     #count the number of bits that a different
                    diffs += 1
                    dbit  = idx
                if diffs >1:break
            if diffs ==1:   #if exactly 1 bit is different between the two, they can be compressed together
                newPatterns.append(p1[:dbit]+'-'+p1[dbit+1:])
                matched+=[x,x+y]
                break
        if x not in matched: newPatterns.append(p1) #if the pattern wasn't matched, just append it as is.

    if matched:         #if reductions occured on this run, then call again to check if more are possible.
        newPatterns = reducePatterns(newPatterns)

    return newPatterns
有没有人对更好/更有效的方法提出建议?
更有效地循环/使用迭代器?Regex魔术?我丢失了一些位操作包?至少可读性更高一点?

您需要的是Python实现


一个快速的谷歌把我带到了这个页面

我还没有完全测试过(它使用递归的方式可能不是很有效),但它似乎很有效,至少满足了你的“更可读”标准:

from itertools import combinations

def collapse(binaries):
    result = set(binaries)
    for b1, b2 in combinations(result, 2): 
        for i in range(len(b1)):
            if b1[:i] + b1[i+1:] == b2[:i] + b2[i+1:]:
                merged = "-".join([b1[:i], b1[i+1:]])
                return sorted(collapse(result ^ {b1, b2, merged}))
    return sorted(result)
示例:

>>> collapse(['1100', '1000', '0100', '0000', '1111', '1011', '0111', '0011'])
['--00', '--11']

>>> collapse(["00", "01", "10", "11"])
['--']

>>> collapse(["011", "101", "111"])
['-11', '101']

嗯。。。从技术上讲,您可以使用
---
:P@Doorknob,这将匹配所有16个可能的4位字符串,但在给定的列表中只有8个。对于第二个示例?不完全是这样,因为
'-'
也会包含像
'1110'
这样不在原始集合中的东西。我也有同样的问题。我尝试了你的代码,但它没有100%正确地完成工作。例如:
reducePatterns(['1100','1000','0100','0000','1111','1011','0111','0011'])
给我输出:
['10--','1100']
。但是它应该是
['10--','1_00']
我想写的:reducePatterns(['1000','1010','1100','1001','1011'])整洁。我想我应该想到这个过程有一个正式的名字,但是我不可能自己偶然发现它。看起来肯定更好,我肯定会借用你的一些想法。我不得不同意你做递归的方式,但是…那里有很多浪费的工作。我也有同样的问题。我尝试了你的代码,但它没有100%正确地完成工作。例如:
collapse(['1100','1000','0100','0000','1111','1011','0111','0011'])
给我输出:
['10--','1100']
。但是它应该是
['10--','100']
,否则你的代码很短而且看起来很好。我不知道你的代码是怎么做的,但也许你知道错误可能是什么?@HighwayJohn你在评论中粘贴了错误的输入了吗?您展示的是我的答案中的一个示例,并且(一旦缺少的引号被修复)继续正确地为我返回
['-00','-11']
。哦,您是对的。我想写:
collapse(['1000','1010','1100','1001','1011'])
那么,
['10--','1100']
就是这个输入的正确表示<代码>['10--','1-00']导致
'1000'
被表示两次。