【问题标题】:Most efficient way to determine the type of sequence in a python list of 0s and 1s?确定0和1的python列表中序列类型的最有效方法?
【发布时间】:2021-03-16 21:33:30
【问题描述】:

假设我们有随机大小的 python 列表,其中的值是 0 和 1 的随机序列。确定序列是否是最多 3 个位置的以下类型之一并为“序列类型”返回以下字符串之一的好方法是什么?:

  • 0(只有0个)[0,0,0]

  • 1(只有1个)[1,1]

  • 01(以 0 开头然后遇到 1 x 后的位数)[0,0,0,0,1]

  • 10(10 的倒数)[1,0,0,0,0]

  • 010(从0开始,在0之后遇到1 x位数,然后在1之后遇到0 x位数)[0,0,0,1,0,1,1,0]

  • 101(与上述相反)[1,1,1,1,1,0,0,1,0,1,0,1]

我可以想到简单的情况,然后是一种简单的方法,即嵌套循环并保留一个计数器,但是有没有更优雅的方法来做到这一点?

def sequence_type(sequence):
    
if 0 not in sequence:
    return '1'

elif 1 not in sequence:
    return '0'

else:
    if sequence[0] == 0:
        # loop through for sequence type 0xx
    elif sequence[0] == 1:
        # loop through for sequence type 1xx

编辑:我们在检查类型时不关心序列末尾的内容,而是查看前 3 个“唯一”数字时的序列。

例如:[0,0,1,0,1,0] 是 010 类型,因为:

  • 0 是第一个数字,是我们的“起点”
  • 然后我们向右走,看到它是另一个 0,所以它不是唯一的,跳过并再次向右移动
  • 然后遇到一个 1,我们记录这个,因为它是唯一的,再次向右移动
  • 看到这个数字是 0 并且是唯一的(我们现在数了 3 个数字),所以模式是 010。

【问题讨论】:

  • 最后两种情况,还有其他限制吗?我们遇到第一个??? ???后面的数字,或者我们可以遇到一个??????,但不是我们的目的,例如,?????????????????????
  • @SamHenke 我做了一个编辑,希望能把事情弄清楚
  • 那么,根据您的编辑,[0,1,0,1] 应该是“010”吧?
  • 正确的@AlainT。

标签: python list algorithm sequence


【解决方案1】:

您可以通过逐位返回序列类型。类型的第一位总是等于第一位。如果在第一个位置之后找到反位,则该类型将有两位或三位数字,第二位是第一位的倒数。如果位在倒数的位置之后,则序列类型为 3 位(再次交替):

def seqType(seq):
    bit = seq[0]                 # seq type starts with first bit
    try: p = seq.index(1-bit)    # search position of inverse bit
    except: return str(bit)      # not found --> single digit type
    if bit not in seq[p+1:]:     # search for initial bit after inverse
        return f"{bit}{1-bit}"   # not found --> two digit type
    return f"{bit}{1-bit}{bit}"  # --> 3 digit type

    

输出:

tests = ([0,0,0],[1,1],[0,0,0,0,1],[1,0,0,0,0],
         [0,0,0,1,0,1,1,0],[1,1,1,1,1,0,0,1,0,1,0,1])    
for seq in tests:
    print(seq,seqType(seq))
    
[0, 0, 0] 0
[1, 1] 1
[0, 0, 0, 0, 1] 01
[1, 0, 0, 0, 0] 10
[0, 0, 0, 1, 0, 1, 1, 0] 010
[1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1] 101 

如果您想要更高级的方法,可以使用 zip 函数计算类型以压缩相同的连续位。压缩序列的前 3 位将对应序列类型:

def seqType(seq):
    return "".join(str(a) for a,b in zip(seq,seq[1:]+[2]) if a!=b)[:3])

或者,如果您喜欢递归解决方案:

def seqType(seq):
    if len(seq) == 1:  return str(seq[0])
    if seq[0]==seq[1]: return seqType(seq[1:])
    return str(seq[0]) + seqType(seq[1:])[:2]

【讨论】:

  • 您的解决方案似乎正在检查列表中的端点。我对帖子进行了编辑,希望能澄清我们不是在查看列表的末尾,而是从左到右走,忽略重复
  • 已根据您对问题所做的精确度进行了调整。
  • 哇,感谢您的多种方法和解释!非常优雅的解决方案,绝对可以击败一百万个 if 语句和循环
【解决方案2】:

如果我理解正确,您正在解析 regular language,因此您可以将其实现为 finite-state automaton

这是一个 C 语言示例:

bool start(char *s) {
  if (*s) {
    if (*s++ == '0') A(s);
    else B(s);
  } else /* empty string doesn't match anything (or it's both a type "0" and type "1" */ 
}

bool A(char *s) {
  if (*s) {
    if (*s++ == '0') A(s);
    else C(s);
  } else /* "0" */
}

bool B(char *s) {
  if (*s) {
    if (*s++ == '0') D(s);
    else E(s)
  } else /* "1" */
}

bool C(char *s) {
  if (*s) {
    if (*s++ == '0') /* "010" */
    else /* Should be illegal. */
  } else /* "01" */
}

bool D(char *s) {
  if (*s) {
    if (*s++ == '0') G(s);
    else /* "101" */
  } else /* "10" */

bool E(char *s) {
  if (*s) {
    if (*s++ == '0') F(s);
    else E(s);
  } else /* "1" */
}

bool F(char *s) {
  if (*s) {
    if (*s++ == '0') /* illegal */
    else /* "101" */
  } else 
}

bool G(char *s) {
  if (*s) {
    if (*s++ == '0') G(s);
    else /* "101" */
  } else /* "10" */
}

这可能不是对有限状态自动机进行编码的最简洁的方法,但沿着这些思路应该可以工作——有限自动机当然是优雅的结构。

你也可以正则表达式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多