从Python列表

时间:2017-02-03 20:21:03

标签: python list nested grouping

我的意见是:

['A', '&', 'B', '|', 'C', '|', '!', 'D', '^', 'E', '&', 'F']

具有操作数(A-F)和根据以下优先级的连接词:

  1. <!/ LI>
  2. &安培;
  3. ^
  4. |
  5. 我需要对项目进行分组,以便在这种情况下输出为:

    [[['A', '&', 'B'], '|', 'C'], '|', [[['!', 'D'], '^', ['E', '&', 'F']]]]
    

    因此,第一个一元否定(!)被分组。然后是二元连词(&amp;),然后是异或(^),最后是disconjunctions(|)。

    使用Python有一种巧妙的方法吗?

    示例代码,应该做的工作但不是那么整洁:

    def grp(lst, operator='|'):
        i, l, r = 0, len(lst), []
        while i < l:
            item = lst[i]
            if item == operator:
                if item == '!':
                    r.append([item, lst[i+1]])
                else:
                    r[-1] = [r[-1], item, lst[i+1]]
                i+=1
            else:
                r.append(item)
            i+=1
        return r
    
    lst = ['A', '&', 'B', '|', 'C', '|', '!', 'D', '^', 'E', '&', 'F']
    print(grp(grp(grp(grp(lst, '!'), '&'), '^'), '|'))
    # -> [[[['A', '&', 'B'], '|', 'C'], '|', [['!', 'D'], '^', ['E', '&', 'F']]]]
    

2 个答案:

答案 0 :(得分:2)

我认为这是半整洁的。它简短而简单。 (虽然效率不高)

tokens = ['A', '&', 'B', '|', 'C', '|', '!', 'D', '^', 'E', '&', 'F']

# operators and number of operands they bind (one to the right, rest to the left):
ops = [ ('!',1), ('&',2), ('^',2), ('|',2) ]

def rindex(lst, x):
    return len(lst) - 1 - lst[::-1].index(x)

for op, n in ops:
    while True:
        try:
            i = rindex(tokens, op)
        except ValueError:
            break
        # "wrap" it:
        tokens[i-n+1 : i+2] = [ tokens[i-n+1 : i+2] ]

tokens
=> [[[['A', '&', 'B'], '|', 'C'], '|', [['!', 'D'], '^', ['E', '&', 'F']]]]

编辑:使用rindex,@ coproc提供。

答案 1 :(得分:1)

这个解决方案概括了grp函数的概念,并且由于它的递归结构,它只需要一次调用:

def lastIndex(lst, x):
    return len(lst) - 1 - lst[::-1].index(x)

def parse(l, binOps=('|', '^', '&')):
  assert len(l) > 0, "malformed input"
  if len(l) == 1:
    assert l[0] != '!' and not l[0] in binOps, "malformed input"
    return l[0]
  if len(binOps) > 0:
    binOp = binOps[0]
    try:
      opPos = lastIndex(l, binOp) # for left-associativity of binary operators
      return [parse(l[:opPos], binOps), binOp, parse(l[opPos+1:], binOps[1:])]
    except ValueError:
      return parse(l, binOps[1:])
  assert l[0] == '!', "malformed input"
  return ['!', parse(l[1:], binOps)]

parse(['A', '&', 'B', '|', 'C', '|', '!', 'D', '^', 'E', '&', 'F'])
# -> [[['A', '&', 'B'], '|', 'C'], '|', [['!', 'D'], '^', ['E', '&', 'F']]]

请注意,解析函数本身并不了解二进制运算符(除了为方便起见而添加的默认参数)。二元运算符及其优先级可以由第二个参数任意指定。在二元运算符的最后一次出现时拆分已解析的标记会使分组成为左关联。 (在第一次出现时拆分解析的标记会使分组成为右关联,这不是通常的默认值,并且会为非交换运算符提供意外结果。)